let在for循环中每次迭代创建独立绑定,使闭包各自捕获当轮i值;而var仅声明一次,所有闭包共享终值;块级作用域确保{}内变量隔离,避免污染与冲突。

ES6 中 let 和 const 改变了变量的作用域模型,直接重塑了闭包的行为逻辑。关键不是“有没有闭包”,而是“闭包捕获的是哪个 i”——而这个差异,源于每次循环迭代是否生成独立的绑定。
for 循环中 let 每次迭代都新建绑定
使用 let i 的 for 循环,JavaScript 引擎会在每次迭代开始时,为 i 创建一个**全新的词法绑定**(不是复制值,也不是重复声明),该绑定仅对该次迭代的循环体生效。
- 这意味着每个回调函数(如定时器、事件处理器或数组中存的函数)所形成的闭包,各自捕获的是属于“自己那一轮”的
i值 - 即使所有函数都在循环结束后才执行,它们仍能正确输出 0、1、2…9,因为每个闭包持有一个独立的
i绑定,而非共享同一个变量 - 这与
var形成鲜明对比:后者只在函数作用域内声明一次i,所有闭包都引用同一个内存位置,最终看到的是循环结束后的终值
块级作用域让闭包“各管各的”
let/const 的块级作用域特性,使 {} 成为真正的隔离单元。只要变量在块内声明,外部就无法访问;更重要的是,嵌套块中同名变量不会污染外层,也不会报错(因为是不同作用域)。
- 例如:
for (let i = 0; i 会打印三次 <code>'abc'—— 内层let i是全新绑定,与外层循环变量无关 - 这种隔离性天然支持闭包按需“快照”:只要函数定义在某个块内,并引用了该块中的 let/const 变量,引擎就会为它保留那个时刻该变量的绑定状态
- 它不依赖立即执行函数(IIFE)这类手动封装技巧,而是语言机制层面的保障
暂时性死区强化了作用域边界
let/const 存在“暂时性死区”(TDZ):从块开始到变量声明语句之间,该变量不可访问,否则报错。
- 这进一步明确了作用域的起始点,避免了 var 的变量提升带来的意外访问
- 对闭包而言,TDZ 意味着:如果一个函数在声明前就被调用,且试图访问尚未初始化的 let 变量,会立即失败,而不是返回
undefined或旧值 - 它让闭包所依赖的变量生命周期更清晰、更可预测——你总能确定“这个变量一定是在这里被创建并初始化的”
const 的行为与 let 在闭包中一致
const 虽然强调“不可重新赋值”,但它同样具有块级作用域和每次迭代新建绑定的特性。
- 在 for 循环中用
const声明计数器会报错(因为每次迭代都要“赋值”,而 const 不允许重复赋值),所以通常不用const i写循环 - 但若用于循环体内固定值(如
const item = arr[i]),它和let item在闭包行为上完全等价:每个闭包拿到的是自己那一轮的item绑定 - 真正重要的是“声明位置 + 关键字类型”,而不是“是不是 const”;只要在块内用 let/const 声明,闭包就能安全捕获


















