嗯,问题在于每个匿名函数内的变量 i
都绑定到函数外部的相同变量。
ES6解决方案: let
ECMAScript 6 (ES6) 引入了 new let
和 const
关键字,它们的作用域与基于 - 的变量不同 var
。例如,在具有基于 let
- 的索引的循环中,循环的每次迭代都会有一个 i
具有循环作用域的新变量,因此您的代码将按预期工作。有很多资源,但我推荐 2ality 的块作用域帖子 ,它是一个很好的信息来源。
for (let i = 0; i < 3; i++) {
funcs[i] = function() {
console.log("My value: " + i);
};
}
但请注意,IE9-IE11 和 Edge 14 之前的 Edge 支持 let
但会出错(它们不会 i
每次都创建一个新的,因此上述所有函数都会像我们使用一样记录 3 var
)。Edge 14 终于做对了。
ES5.1解决方案:forEach
由于该函数的可用性相对较高 Array.prototype.forEach
(2015 年),值得注意的是,在主要涉及对值数组进行迭代的情况下,它 .forEach()
提供了一种干净、自然的方式来为每次迭代获取不同的闭包。也就是说,假设您有某种包含值(DOM 引用、对象等)的数组,并且出现了为每个元素设置特定回调的问题,您可以这样做:
var someArray = [ /* whatever */ ];
// ...
someArray.forEach(function(arrayElement) {
// ... code code code for this one element
someAsynchronousFunction(arrayElement, function() {
arrayElement.doSomething();
});
});
这个想法是,循环中使用的回调函数的每次调用 .forEach
都将是其自己的闭包。传递给该处理程序的参数是特定于迭代的特定步骤的数组元素。如果它在异步回调中使用,它不会与迭代其他步骤中建立的任何其他回调发生冲突。
如果您恰好使用 jQuery,该 $.each()
函数可以为您提供类似的功能。
经典解决方案:闭包
您要做的是将每个函数内的变量绑定到函数外部的单独的、不变的值:
var funcs = [];
function createfunc(i) {
return function() {
console.log("My value: " + i);
};
}
for (var i = 0; i < 3; i++) {
funcs[i] = createfunc(i);
}
for (var j = 0; j < 3; j++) {
// and now let's run each one to see
funcs[j]();
}
由于 JavaScript 中没有块作用域 - 只有函数作用域 - 通过将函数创建包装在新函数中,您可以确保 \'i\' 的值保持如您所愿。