JavaScript闭包中循环变量引用共享陷阱的根源是var声明的变量具有函数作用域且被所有迭代闭包共享;推荐用let声明实现每次迭代独立绑定,或用IIFE、数组方法、显式复制值等方式解决。

在 JavaScript 闭包中,循环变量引用共享陷阱的根源是:var 声明的变量具有函数作用域,且被所有迭代闭包共享。常见表现是,循环结束后所有闭包都捕获到循环变量的最终值(如 for 循环结束时 i === 5),而非各自迭代时的值。
用 let 替代 var 声明循环变量
let 在每次迭代中创建新的绑定,每个闭包捕获的是当前轮次独立的变量实例,这是最简洁、推荐的现代解法。
✅ 正确写法:
for (let i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100); // 输出 0, 1, 2
}
为闭包创建独立作用域(兼容旧环境)
若需支持老旧环境(如 IE 或严格 ES5 环境),可通过立即执行函数(IIFE)将当前变量值作为参数传入,形成新作用域。
立即学习“Java免费学习笔记(深入)”;
✅ 兼容写法:
- 使用 IIFE 封装 i 的副本:
for (var i = 0; i < 3; i++) {
(function (index) {
setTimeout(() => console.log(index), 100);
})(i);
}
- 或直接返回函数并立即调用:
for (var i = 0; i < 3; i++) {
setTimeout((function (index) {
return () => console.log(index);
})(i), 100);
}
用数组方法替代传统 for 循环
forEach、map 等数组方法天然提供块级作用域参数,每个回调函数接收独立的当前项和索引,无需额外处理。
✅ 更语义化、安全的写法:
[0, 1, 2].forEach((i) => {
setTimeout(() => console.log(i), 100); // 输出 0, 1, 2
});
注意:确保遍历的是真实数组(而非类数组对象),必要时可用 Array.from() 转换。
避免在闭包中直接引用循环变量
如果必须用 var 且无法改结构,可显式复制值到局部常量或参数中,切断对循环变量的引用链。
✅ 安全模式:
for (var i = 0; i < 3; i++) {
const current = i; // 创建不可变副本
setTimeout(() => console.log(current), 100);
}
也可用解构赋值或函数参数默认值等方式固化值,核心原则是:让闭包捕获的是值的快照,而非变量的引用。


















