Javascript 将循环中的闭包分配给.prototype

Javascript 将循环中的闭包分配给.prototype,javascript,closures,Javascript,Closures,我正在开发一个Javascript库,在这个库中我不能污染全局名称空间,并且必须在一个或两个全局变量中包含我的所有变量。我目前遇到了一个特殊情况,我需要使用闭包,但我通常尝试的方法不起作用,这让我困扰了一段时间。搜索只产生了我通常使用的传统闭包方法 [...] addFilters: function(filters) { for(filter in filters) { this.filters[filter] = filters[filter]; this.Image.p

我正在开发一个Javascript库,在这个库中我不能污染全局名称空间,并且必须在一个或两个全局变量中包含我的所有变量。我目前遇到了一个特殊情况,我需要使用闭包,但我通常尝试的方法不起作用,这让我困扰了一段时间。搜索只产生了我通常使用的传统闭包方法

[...]
addFilters: function(filters) {
  for(filter in filters) {
    this.filters[filter] = filters[filter];
    this.Image.prototype[filter] = function() { //closures, how do they work?
      return (function(image, filter, arguments) {
        image.addQueue(filter, arguments);
      })(this, filter, arguments);
    };
  }
},
[...]
在上面的代码段中,Image.prototype函数(和Image.addQueue)没有正确捕获“filter”,因此每次都将其设置为for..In迭代中的最后一个过滤器

在此填写代码,并突出显示相关部分:

现场演示:
你的工厂功能有点不稳定。您需要命名它的参数,而自调用的执行不正确。如果您只使用一个单独的函数来生成分配给
this.Image.prototype[filter]
的函数,这会更加明显

function generateProtoFunc(image, filter, arguments) {
    return function(filter, arguments) {
        image.addQueue(filter, arguments);
    };
}

// snip...

for (filter in filters) {
    this.filters[filter] = filters[filter];
    this.Image.prototype[filter] = generateProtoFunc(this, filter, arguments);
}

下面是使用即时函数调用的正确方法:

for (filter in filters) {
    this.filters[filter] = filters[filter];
    this.Image.prototype[filter] = (function(image, filter, arguments) {
        return function(filter, arguments) {
            image.addQueue(filter, arguments);
        };
    })(this, filter, arguments);
}

闭包绑定到声明它的作用域,而不是该作用域中的变量在声明时所具有的特定值。
我正在解释为什么你的代码不起作用。通过了解原因,您会发现有一种更简单的方法可以做到这一点。
在每个FOR循环中声明的所有函数都绑定到相同的作用域(addFilters函数作用域),因此在执行闭包时,它们从相同的作用域读取变量,从而获得相同的值。
因此,这里的关键是将每个闭包绑定到不同的作用域,这就是通过将闭包包装在匿名函数中所做的:即,为每个闭包创建一个唯一的作用域

但是。。。创建作用域是否需要匿名函数调用?
答案是否定的。
您可以使用
with
语句以可读性强的方式创建范围

以下是使用该方法的代码:

[...]
addFilters: function(filters) {
    for(filter in filters) {
        this.filters[filter] = filters[filter] ;
        with({ _filter: filter }) // with this you create a new scope with the local variable `_filter` holding the value of `filter`
            this.Image.prototype[filter] = function(image, arguments){ image.addQueue(_filter, arguments) } ; // and this closure is bound to the new scope
    }
},
[...]
变量
image
arguments
是闭包的参数,因此不需要将它们添加到新范围。一旦实际执行闭包,就传递这些值


此外,您不需要以不同的方式命名
\u filter
变量。你可以把它命名为
filter
,它只会给outter scope的
filter

这就是我一直做的事情,我以前从来没有遇到过这个问题。你能告诉我我做错了什么吗?那不会产生同样的结果吗?我只是简单地避免使用另一个构造函数,将匿名函数用括号括起来,这样我就可以立即调用它。@Ian:没有,因为你没有正确地编写它。我将更新我的答案以显示差异。这是一种有趣的方法,但我听说with()的功能在不同的浏览器中是不一致的。我没有听说过。我已经为公共网站做过很多次了,而且效果一直不错。