let 声明的循环变量每次迭代都创建独立词法环境,使 settimeout 正确输出 0、1、2;var 则共享变量导致全输出 3;该机制仅适用于 for(含 for...of/in),while/do-while 需手动块作用域模拟。

在 JavaScript 中,用 let 声明循环变量(如 for (let i = 0; i )能为每次迭代创建**独立的块级<a style="color:#f60; text-decoration:underline;" title="作用域" href="https://m.php.cn/zt/35787.html" target="_blank">作用域</a>**,从而避免传统 <code>var 声明导致的闭包问题。
为什么 let 能隔离每次迭代的作用域
let 在 for 循环中不是简单地在循环外声明一次,而是在**每次迭代开始时,都创建一个新的绑定(binding)**。这意味着每个循环轮次的 i 实际上是不同的变量,彼此互不影响。
这和 var 的函数作用域、变量提升行为完全不同——var i 全局只有一份,所有异步回调引用的都是同一个 i 的最终值。
典型场景:定时器中正确输出 0、1、2
下面代码使用 let,能按预期打印 0、1、2:
for (let i = 0; i setTimeout(() => console.log(i), 100);
}
如果换成 var i,三个 setTimeout 都会输出 3(因为循环结束时 i === 3,且只有一个 i)。
底层机制:每次迭代都有独立的词法环境
ES 规范规定:for (let x;;) 的每次迭代都会创建一个新的词法环境(Lexical Environment),其中包含该次迭代专属的 x 绑定。因此:
- 每个箭头函数或普通函数内部捕获的
i,指向各自迭代对应的绑定; - 即使在循环体内用
let声明其他变量(如let msg = 'item' + i),它也属于当次迭代的块作用域; - 这种行为对
for...of和for...in同样适用(只要用let声明遍历变量)。
注意:仅限 for 语句本身,不包括 while 或 do-while
let 的迭代级绑定是 for 语句的特殊处理,while 或 do-while 不具备此特性:
let j = 0;
while (j setTimeout(() => console.log(j), 100); // 全部输出 3
j++;
}
若要在 while 中实现类似效果,需手动用 { let j = ... } 块或立即执行函数包裹。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











