您引用的代码没有执行您列出的操作,您可能丢失了一些简化问题的内容。
但是,此代码将具有您所描述的效果:
for(j in groups){
doSomething(function() {
// Callback for `doSomething`
console.log(j, somefunction(groups[j]));
});
}
请注意,现在我正在创建一个函数(无论doSomething
做什么都是回调),而不仅仅是调用一个。
发生这种情况的原因是正在创建的函数具有对变量(以及执行上下文中的所有其他内容)的持久引用,而不是创建函数时的副本。它被称为对该执行上下文的闭包。所以你的循环运行,一系列调用开始一系列事情,然后当回调被调用时,是3,所以它们都是一样的。j
doSomething
j
通常的解决方案是创建函数来关闭在调用之前不会更改的内容,如下所示:
for(j in groups){
doSomething(makeCallback(j));
}
function makeCallback(jarg) {
return function() {
console.log(jarg, somefunction(groups[jarg]));
};
}
现在,我们jarg
在回调中使用,而不是j
. 因为jarg
它是调用上下文的一部分makeCallback
,所以它在我们创建函数和稍后调用它之间不会改变。
将数据绑定到函数的另一种方法是使用Function#bind
(有效地在后台创建闭包),这是 NodeJS 中可用的 ES5 功能,因为 V8 引擎具有它。看起来是这样的:
for(j in groups){
doSomething(function(jarg) {
// Callback for `doSomething`
console.log(jarg, somefunction(groups[jarg]));
}.bind(this, j)); // <== Note the bind
}
或不那么令人困惑(并且很可能更有效):
for(j in groups){
doSomething(handler.bind(this, j));
}
function handler(jarg) {
// Callback for `doSomething`
console.log(jarg, somefunction(groups[jarg]));
}
更多关于闭包: