题目 13 / 14
为什么把 var 换成 let 就能修复这个 setTimeout 循环?
知识点: 闭包
let 会在每次迭代时创建一个全新的 i 绑定,因此每个回调闭包捕获的都是自己独立的值。
使用执行可视化器解题在下方逐步观察每个绑定、函数调用和控制台输出。预测输出结果
预测输出。现在循环用的是 let,每个回调还会读到同一个最终的 i 吗?
for (let i = 0; i < 3; i++) {
setTimeout(function() {
console.log(i);
}, 100);
}查看答案与完整解析
正确输出
0
1
2为什么会这样
使用 let 的 for 循环会在每次迭代时创建一个全新的 i 绑定,其初始值从上一次迭代的值复制而来。
每次调用 setTimeout 注册的回调闭包捕获的都是那一次迭代专属的绑定,而不是一个共享绑定,因此三个回调对应三个独立的环境。
循环结束后,定时器队列依次执行这些回调,每个回调都在自己独立的绑定中查找 i,打印出它被创建时的值:先是 0,然后是 1,最后是 2。
这道题考察什么
- let 是块级作用域,每次迭代都有新绑定
- 捕获不同绑定的闭包彼此独立
- 与 var 版本对比:那里所有回调共享同一个绑定
运行环境前提
可视化器把每次 let 迭代都建模为独立的词法环境,这与 Node.js、浏览器以及其他标准 JavaScript 运行时中按迭代创建绑定的行为一致。