javascript - 为什么 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;
更新循环变量好像i
ini+=1;
不是每次迭代的本地副本,并且在setTimeout
回调中表现得好像i
是每次迭代的本地副本。
解决方案
当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
。
推荐阅读
- c# - C# 只显示 CMD 中的一个特定行
- windows - .Net Core RRS 提要中的 RNGCryptoServiceProvider
- javascript - 使用节点缓存进行缓存不会持久化数据
- flutter - 如何在语义树中将 Flutter 小部件划分为单独的节点
- r - 函数不将调用参数视为 R 中的值
- r - 在 R 中自动安装所有必需的包
- angular - 找不到与@babel/helper-validator-identifier@^7.9.5 匹配的版本
- macos - 设置 MATLAB 在 macOS 上使用的系统 shell
- ansible - Ansible 不会覆盖现有文件
- java - progressBar setVisibility VISIBLE