Javascript 将循环中的闭包分配给.prototype
我正在开发一个Javascript库,在这个库中我不能污染全局名称空间,并且必须在一个或两个全局变量中包含我的所有变量。我目前遇到了一个特殊情况,我需要使用闭包,但我通常尝试的方法不起作用,这让我困扰了一段时间。搜索只产生了我通常使用的传统闭包方法Javascript 将循环中的闭包分配给.prototype,javascript,closures,Javascript,Closures,我正在开发一个Javascript库,在这个库中我不能污染全局名称空间,并且必须在一个或两个全局变量中包含我的所有变量。我目前遇到了一个特殊情况,我需要使用闭包,但我通常尝试的方法不起作用,这让我困扰了一段时间。搜索只产生了我通常使用的传统闭包方法 [...] addFilters: function(filters) { for(filter in filters) { this.filters[filter] = filters[filter]; this.Image.p
[...]
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()的功能在不同的浏览器中是不一致的。我没有听说过。我已经为公共网站做过很多次了,而且效果一直不错。