var在循环中出问题是因为其函数作用域导致所有异步回调共享同一变量i,循环结束时i已为终值;用iife闭包、let块级作用域或闭包工厂均可捕获每次迭代的当前值。

JavaScript 中循环里用 var 声明变量,常导致所有回调共享同一个变量值(比如 for 循环中异步操作输出全是最后一个索引),本质是 var 的函数作用域 + 变量提升造成的。闭包能解决这个问题,核心是让每次迭代捕获当前的值。
为什么 var 在循环里会出问题
var 是函数作用域,不是块级作用域。整个 for 循环共用一个 i 变量。当循环结束、异步任务(如 setTimeout)执行时,i 已变成终值(比如 3),所以所有回调都打印同一个数。
例如:
for (var i = 0; i console.log(i), 100); // 输出:3, 3, 3 }
用立即执行函数(IIFE)+ 闭包捕获当前值
在每次迭代中,用一个立即执行函数把当前的 i 作为参数传入,函数内部形成闭包,保存该次迭代的值。
- 参数
current在每次调用时绑定当时的i值 - 内部函数引用
current,就形成了闭包,不会受后续i变化影响
for (var i = 0; i console.log(current), 100); })(i); // 把当前 i 传进去 }
输出:0, 1, 2 ✅
用 let 替代 var(更现代、更直接)
let 是块级作用域,每次循环都会为 i 创建新绑定,每个迭代里的 i 独立存在。虽然这不是“手动写闭包”,但背后机制依赖词法环境和闭包原理,效果等价且更简洁。
for (let i = 0; i console.log(i), 100); // 输出:0, 1, 2 }
封装成可复用的闭包工厂
如果逻辑复杂,可以把闭包逻辑抽象出来,提高可读性和复用性:
- 定义一个返回函数的函数,接收当前值并返回闭包内函数
- 在循环中调用它,生成带捕获值的回调
function makeLogger(value) {
return () => console.log(value);
}
for (var i = 0; i
不复杂但容易忽略——关键不在“写多深的闭包”,而在理解变量绑定时机和作用域边界。用 let 是首选;需要兼容老环境或教学演示时,IIFE 闭包就是清晰可靠的解法。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











