JavaScript循环变量捕获问题的本质是缺乏独立词法环境,解决核心是为每次迭代创建独立块级作用域+闭包绑定;let声明实现每次迭代新绑定,IIFE+var模拟闭包,forEach等高阶函数天然提供独立作用域。

在 JavaScript 中,循环中变量捕获问题(比如 var 声明的变量被所有迭代共享)的本质,是缺乏独立的词法环境。解决它,核心就是为每次迭代创建**独立的块级作用域 + 闭包绑定**,让每个回调或函数记住自己那一轮的值。
用 let 声明实现块级作用域隔离
let 在每次循环迭代中都会声明一个**新的绑定**,每个迭代有自己的词法环境。这是最简洁、现代的解法。
- for 循环中每次迭代的
let i是不同变量,不是复用同一个内存地址 - 因此传给定时器、事件监听器或异步回调时,能自然捕获当前轮次的值
- 示例:
for (let i = 0; i setTimeout(() => console.log(i), 100); // 输出 0, 1, 2
}
```
用立即执行函数(IIFE)+ var 模拟闭包绑定
ES5 时代常用方案:把当前值作为参数传入 IIFE,在其内部形成闭包,把值“锁住”。
- IIFE 执行时立即捕获当前
i的值,并作为形参保存在自己的作用域中 - 内部函数通过闭包访问这个参数,不受外部
i后续变化影响 - 示例:
for (var i = 0; i (function (index) {
setTimeout(() => console.log(index), 100);
})(i);
}
```
用 forEach 或其他高阶函数替代 for 循环
数组方法天然提供独立作用域——每次回调都是新函数调用,参数本身就是本轮的值。
立即学习“Java免费学习笔记(深入)”;
- 避免手动管理索引和作用域,语义清晰、不易出错
- 适用于已有数组或可转为数组的数据(如
Array.from({length:3})) - 示例:
[0, 1, 2].forEach(i => {
setTimeout(() => console.log(i), 100); // 输出 0, 1, 2
});
```
注意:不要误用 const 替代 let 控制循环变量
const 不能用于传统 for 循环的计数器,因为它的值不可重新赋值。
for (const i = 0; i 会报错(<code>i++违反 const 约束)- 但可用于
for...of或forEach中的元素绑定,此时每次迭代确实新建 const 绑定 - 示例:
for (const i of [0, 1, 2]) {
setTimeout(() => console.log(i), 100); // 正确,输出 0, 1, 2
}
```


















