首页 > 解决方案 > 为什么 i 在 "for (let i..."

问题描述

考虑以下代码片段:

for (let i = 0; i < 5; i++) {
  i+=1;
  setTimeout(() => console.log(i), 100);
}
console.log('after for loop');

如果let i每次迭代都创建一个新的块范围变量,我希望它输出:

1
2
3
4
5

因为,作为一个新的块范围变量,i+=1;只会对我的本地副本进行更改i。此外,如果i是一个新的块作用域变量,这将解释为什么setTimeout回调不记录“6”3 次(就像它在let i更改为 时一样var i)。

如果它有帮助,这就是我想象的如果它为每次迭代创建一个新的块范围变量,它将在幕后做的事情:

for (let I = 0; I < 5; I++) {
  let i = I;
  i+=1;
  setTimeout(() => console.log(i), 100);
}
console.log('after for loop');

然而,上面的代码片段实际上输出:

1
3
5

如果在所有迭代之间共享,这将是有意义i的,除非在所有迭代i之间共享,为什么setTimeout回调不会打印相同的数字 3 次?

简而言之,我的问题是:

为什么,在上面的代码片段中,i+=1;更新循环变量好像iini+=1;不是每次迭代的本地副本,并且在setTimeout回调中表现得好像i是每次迭代的本地副本。

标签: javascriptfor-loop

解决方案


for循环声明中声明的变量循环体内重新分配时,该重新分配将持续到下一次迭代。如果你看一下Babel是如何编译它的,那就更清楚了:

for (let i = 0; i < 5; i++) {
  i+=1;
  setTimeout(() => console.log(i), 100);
}
console.log('after for loop');

结果是

"use strict";

var _loop = function _loop(_i) {
  _i += 1; // <---------------
  setTimeout(function() {
    return console.log(_i);
  }, 100);
  i = _i; // <---------------
};

for (var i = 0; i < 5; i++) {
  _loop(i);
}

console.log("after for loop");

如果您在循环体的同步执行i 之外for更改或记录,它将(本质上)引用_i上述内容,就像一个完全独立的块范围变量一样。但是,如果您在同步循环体内进行更改i for下一次迭代将从 changed 开始i


推荐阅读