Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/400.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 可以使用多个闭包向函数';什么样的范围可以简化?_Javascript - Fatal编程技术网

Javascript 可以使用多个闭包向函数';什么样的范围可以简化?

Javascript 可以使用多个闭包向函数';什么样的范围可以简化?,javascript,Javascript,我试图将两个变量传递给filereader回调。本质上,我是在文件上循环并显示它们的缩略图;要实现这一点,我需要两个变量(在本例中,parent和canvas)。下面的代码是有效的,但我想确保我未来的自己不会恨我现在的自己 我假设在不覆盖this的情况下将两个变量传递到回调函数的作用域是一种相当常见的情况 这段代码使用了一个名称空间(父级),这是可以避免的,但我仍然想知道如何将两个变量传递到回调函数中 reader.onload = (function (parent) { // even fu

我试图将两个变量传递给
filereader
回调。本质上,我是在文件上循环并显示它们的缩略图;要实现这一点,我需要两个变量(在本例中,
parent
canvas
)。下面的代码是有效的,但我想确保我未来的自己不会恨我现在的自己

我假设在不覆盖
this
的情况下将两个变量传递到回调函数的作用域是一种相当常见的情况

这段代码使用了一个名称空间(父级),这是可以避免的,但我仍然想知道如何将两个变量传递到回调函数中

reader.onload = (function (parent) { // even funkier closure to access the parent, the canvas, and the file
    return function(canvas) { // funky closure to be able access the canvas and file
        return function(r) {
            canvas.sourceImage.src = r.target.result;
            parent.functions.render(canvas);
            parent.functions.preview(canvas, canvas.sourceImage.width/10, canvas.sourceImage.height/10);
        };
    }(parent.canvases[j]);
})(parent);

reader.readAsDataURL(file);

根据注释,这里是完整的代码。我不是特别想要代码审查(
有一个堆栈!
),但是任何反馈都是非常感谢的

(function () {
    this.readFiles = function (parent) {
        var files = parent.fileInput.files;
        var j = parent.canvases.length; // so we don't overwrite old previews
        for (var  i = 0; i < files.length; i++, j++) {
            var file = files[i];
            var reader = new FileReader;

            var canvas = document.createElement('canvas');
            canvas.id = "previewCanvas" + j;
            canvas.className = parent.canvasClasses;
            canvas.width = 100;
            canvas.height = 100;
            parent.previewWrapper.appendChild(canvas);

            /* Initialize Canvases for each file */
            parent.canvases[j] = this.create(document.getElementById('previewCanvas' + j));

            reader.onload = (function (parent) { // even funkier closure to access the parent, the canvas, and the file
                return function(canvas) { // funky closure to be able access the file
                    return function(r) {
                        canvas.sourceImage.src = r.target.result;
                        parent.functions.render(canvas);
                        parent.functions.preview(canvas, canvas.sourceImage.width/10, canvas.sourceImage.height/10);
                    };
                }(parent.canvases[j]);
            })(parent);

            reader.readAsDataURL(file);
        }
    }
}).apply(Canvas.functions);
(函数(){
this.readFiles=函数(父级){
var files=parent.fileInput.files;
var j=parent.canvases.length;//因此我们不会覆盖旧的预览
对于(var i=0;i
基本上,您可以去掉大部分闭包和其他一些代码

这应该行得通,除非我引入了任何bug。。。您注意到的两个bug现在已修复,感谢您捕获它们!:-)

请注意:

您不需要将
Canvas.functions
转换为
this
的最外层生命。直接使用
Canvas.functions
。这也消除了
这个
在回调中不正确的可能性(这似乎不是问题,但它有助于保持简单)

您不需要
j
变量
parent.canvases.length始终与
j
的值相同

如果使用
.forEach()
而不是
for
循环,则会对
.forEach()
回调中声明的所有局部变量进行闭包。这真的是你唯一需要的结束

正如您所指出的,像
FileReader
这样的“类似数组”的对象可能没有
.forEach()
方法。有几种方法可以解决这个问题。一种是为
循环编写一个普通的
,并在其中调用一个函数,例如

var files = parent.fileInput.files;
for( var i = 0;  i < files.length;  i++ ) {
    doFile( files[i] );
}

function doFile( file ) {
    ...
}
var files=parent.fileInput.files;
对于(var i=0;i
这可以通过内联函数expresion来实现,但我喜欢使用单独的命名函数语句来实现这一点——它看起来更清晰一些。(这里的一个警告是,如果
for
块,则不要将函数语句本身放在嵌套块中,如
——浏览器不能一致地处理它——它需要直接放在外部函数中

reader.onload = (function (parent) { // even funkier closure to access the parent, the canvas, and the file
    return function(canvas) { // funky closure to be able access the canvas and file
        return function(r) {
            canvas.sourceImage.src = r.target.result;
            parent.functions.render(canvas);
            parent.functions.preview(canvas, canvas.sourceImage.width/10, canvas.sourceImage.height/10);
        };
    }(parent.canvases[j]);
})(parent);

reader.readAsDataURL(file);
或者,使用
Array.prototype.forEach.call()
让您在类似数组的对象上使用
forEach
。我在上面更新的代码中使用了这种方法,定义了一个独立的
forEach()
函数。您可以将
Array.prototype.forEach.call()放入
直接内联,但我认为将其封装在函数中更为简洁。当然,如果您使用的是下划线或LoDash之类的库,则可以使用方便的迭代器,如
。.each()

不需要使用
document.getElementById()
来获取对当前画布的引用,因为在
canvas
变量中已经有了它

onload()
回调函数中,您不需要任何一个嵌套闭包。该函数已经可以访问必要的变量

代码似乎将名称
canvas
用于两种截然不同的内容。第一种是在顶部创建的实际
canvas
元素,第二种是
canvas.functions.create(canvas)的返回值
。为了避免混淆,我将第二个名称重命名为
fileCanvas
。您可能会想出一个更好的名称,只是不要称它为
canvas


onload
回调中,
r.target
是与
reader
相同的对象,因此您可以直接使用它。如果您确实在这样的事件处理程序中使用参数,我建议将其称为
event
(或者
e
,如果您需要一个简短的名称)因为这是更常见的。

尽管@MichaelGeary主要通过重构代码来回答我的问题,但标题问题的答案是外部函数立即执行,并且可以访问当前变量:

reader.onload = (function (parent) { 

   var canvas = parent.canvases[j];
   // put more variables ad nauseum here. 
   // They will be passed to the return function without being changed.

   return function(r) {
        canvas.sourceImage.src = r.target.result;
        parent.functions.render(canvas);
        parent.functions.preview(canvas, [...]);
        };
})(parent);

这样,您可以使用回调中需要的计数器和其他变量。

您可以始终传递包含两个变量的单个对象。