我正在开发一个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迭代中的最后一个过滤器。
此处填写完整代码并突出显示相关部分: http://pastebin.com/UVFTVPkh
答案 0 :(得分:1)
你的工厂功能有点不稳定。您需要为其参数命名,并且不正确地执行自调用。如果您只使用单独的函数来生成分配给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);
}
答案 1 :(得分:0)
闭包绑定到声明它的范围,而不是声明时该范围内变量的特定值。
我在解释为什么你的代码不起作用。通过了解原因,你会发现有一种更简单的方法可以做到这一点
您在每个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
是闭包的参数,因此您无需将它们添加到新范围。实际执行闭包后,您将传递这些值。
此外,您不需要以不同方式命名_filter
变量。您可以将其命名为filter
,它只会影响范围的filter
。