用 let 声明循环变量可解决闭包中定时器输出全为最后一个值的问题:var 声明导致变量提升与共享绑定,而 let 每次迭代创建独立绑定,使每个回调捕获当次的 i 值。

用 let 声明循环变量,就能让每次迭代拥有独立的绑定,从而解决闭包中定时器输出全是最后一个值的问题。
问题本质:var 声明导致变量提升与共享绑定
var 声明的变量在函数作用域内被提升,且整个循环共用同一个变量实例。即使在 for 循环中多次执行 setTimeout,所有回调都引用同一个 i 变量——等定时器真正执行时,循环早已结束,i 已变成最终值(比如 5)。
let 的块级作用域特性是关键
let 在每次循环迭代中都会为变量创建一个新的绑定(不是拷贝值,而是新的词法环境绑定)。每个 setTimeout 回调捕获的是当次迭代独有的 i,因此能正确输出 0、1、2、3、4。
Java开发手册规约集合,基于阿里巴巴Java开发手册(嵩山版)。 涵盖7大维度:编程规约、异常日志、单元测试、安全规约、MySQL数据库、工程结构、设计规约。 当用户需要:(1) 编写或审查Java代码 (2) 检查命名/代码规范 (3) 处理异常和日志 (4) 编写单元测试 (5) 安全编码 (6) 数据库设...
- 不需要额外包裹 IIFE(立即执行函数)
- 不依赖
bind或额外参数传值 - 语义清晰,符合直觉
对比写法示例
错误写法(var):
立即学习“Java免费学习笔记(深入)”;
for (var i = 0; i < 5; i++) {
setTimeout(() => console.log(i), 100);
}
// 输出:5, 5, 5, 5, 5
正确写法(let):
for (let i = 0; i < 5; i++) {
setTimeout(() => console.log(i), 100);
}
// 输出:0, 1, 2, 3, 4
注意事项
- 必须用
let(或const,如果变量不重赋值),不能混用var声明循环变量 - 该机制依赖 ES6+ 环境;若需兼容老浏览器,仍需 IIFE 等降级方案
- 不只是
setTimeout,所有异步回调(如Promise.then、事件监听器)中引用循环变量时,let同样有效

















