您引用的代码没有按照您列出的那样做,您可能丢失了一些简化问题的东西。
不过,此代码会产生您所描述的效果:
for(j in groups){
doSomething(function() {
// Callback for `doSomething`
console.log(j, somefunction(groups[j]));
});
}
请注意,现在我正在创建一个函数(doSomething 所做的任何回调),而不仅仅是调用一个。
发生这种情况的原因是正在创建的函数对j 变量(以及执行上下文中的所有其他内容)有一个持久引用,而不是副本从创建函数时开始。它在那个执行上下文上被称为 closure。所以你的循环运行,对doSomething 的一系列调用开始了一系列的事情,然后当回调被调用时,j 是 3,所以它们都是一样的。
通常的解决方案是创建函数来关闭在调用之前不会更改的内容,如下所示:
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]));
}
更多关于闭包的信息: