循环内的函数
长期以来,var
的特点使得循环变量在循环作用域之外仍然可被访问,于是在循环内创建函 数就变得很有问题。考虑如下代码:
var funcs = [];
for (var i = 0; i < 10; i++){
funcs.push(function(){
console.log(i);
});
}
funcs.forEach(
founction(func){
func(); //输出数值 “10” 十次
}
);
你原本可能预期这段代码会输出0
到9
的数值,但它却在同一行将数值10
输出了十次。这是 因为变量i
在循环的每次迭代中都被共享了,意味着循环内创建的那些函数都拥有对于同一 变量的引用。在循环结束后,变量i
的值会是10
,因此当console.log(i)
被调用时, 每次都打印出10
。
为了修正这个问题,开发者在循环内使用立即调用函数表达式(IIFEs),以便在每次迭代中 强制创建变量的一个新副本,示例如下:
var funcs = [];
for (var i=0; i < 10; i++){
funcs.push((function(value){
return function(){
console.log(value);
}
}(i)));
}
funcs.forEach(
function(func){
func(); // 从 0 到 9 依次输出
}
)
这种写法在循环内使用了IIFE
。变量i
被传递给IIFE
,从而创建了value
变量作为自身 副本并将值存储于其中。value
变量的值被迭代中的函数所使用,因此在循环从0
到9
的过 程中调用每个函数都返回了预期的值。幸运的是,使用let
与const
的块级绑定可以在 ES6
中为你简化这个循环。