循环内的JavaScript闭包 - 简单实用的例子


循环内的JavaScript闭包 - 简单实用的例子


经典解决方案:闭包

你想要做的是将每个函数中的变量绑定到函数之外的一个单独的,不变的值:

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++) {
    funcs[j]();                        // and now let's run each one to see
}

2015解决方案: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()函数会为你提供类似的功能。

ES6解决方案: let

ECMAScript 6(ES6)是最新版本的JavaScript,现在开始在许多常绿浏览器和后端系统中实现。还有像Babel这样的转发器会将ES6转换为ES5,以允许在旧系统上使用新功能。

ES6引入了新的let和const关键字,其范围与var基于变量的不同。例如,在具有let基于索引的循环中,循环中的每次迭代都将具有一个新值,i其中每个值都在循环中作用域,因此您的代码将按预期工作。有很多资源,但我建议将2ality的区块范围发布作为一个很好的信息来源。

for (let i = 0; i < 3; i++) {
    funcs[i] = function() {
        console.log("My value: " + i);
    };
}

但是要注意,在Edge 14支持之前IE9-IE11和Edge let会出现上述错误(它们i每次都不会创建新的,所以上面的所有函数都会像我们使用的那样记录3 var)。Edge 14最终做对了。