let 声明可解决循环闭包问题,因其在每次迭代中为变量创建独立的块级绑定,使每个回调捕获各自迭代的值;而 var 是函数作用域,所有迭代共享同一变量引用,异步执行时仅能访问终值。

用 let 声明循环变量,能天然解决传统 var 在闭包中捕获同一引用导致的“全部输出最后一个值”的问题。
为什么 var 在循环中会出问题
var 是函数作用域,且存在变量提升。在 for 循环里用 var 声明变量,整个循环共用一个变量绑定。当异步操作(如 setTimeout)执行时,循环早已结束,i 的值固定为终值(比如 5),所有回调都访问这个最终值。
例如:
❌ 错误写法(var)for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100); // 输出:3, 3, 3
}
let 如何解决——块级绑定 + 每次迭代独立绑定
let 具有块级作用域,且在 for 循环中,每次迭代都会为 let 变量创建一个**新的绑定**(不是拷贝值,而是新绑定)。因此每个回调函数捕获的是各自迭代对应的独立变量实例。
立即学习“Java免费学习笔记(深入)”;
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
✅ 正确写法(let):
for (let i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100); // 输出:0, 1, 2
}
这背后是 ES6 规范对 for 语句的特殊处理:每次迭代都会重新声明并初始化 let 变量,形成逻辑上的“新词法环境”。
不只 for 循环:其他块级场景同样适用
只要在块级作用域内用 let 声明变量,并在该块内定义函数,就能确保该函数“记住”当时块中的变量值。
- 在
if或{}块中声明let变量,内部函数可安全引用 - 动态生成事件处理器时,用
let绑定参数比手动写 IIFE 更简洁 - 替代老式 IIFE 写法:
(function(i) { ... })(i)→ 直接let i = ...即可
注意边界情况:let 不能解决所有闭包传参问题
let 主要解决的是“循环中变量被异步回调共享”的典型场景。但它不自动绑定函数参数或对象属性:
- 如果把
let变量作为参数传入函数,而函数内部又修改了它(如对象属性),仍可能产生意外交互 - 若需冻结数据,应配合
const、结构赋值或Object.freeze() - 在非标准循环(如
while)中,需手动用{ let i = ...; ... }建立块作用域

















