循环中闭包变量共享问题的关键在于变量声明方式与作用域绑定不匹配;用 let 替代 var 可解决 for 循环中 i 的共享问题,因其块级作用域为每次迭代创建独立绑定;es5 兼容时可用 iife 传参隔离作用域,或改用 foreach/map 等高阶函数,本质是通过新函数作用域捕获值的副本而非引用。

循环中闭包变量共享问题,核心不是“闭包有问题”,而是变量声明方式和作用域绑定没对齐。关键在让每个异步回调拿到它该有的那个值,而不是大家抢同一个i。
用 let 替代 var 声明循环变量
let 是块级作用域,每次迭代都会创建一个新的绑定,闭包捕获的是各自独立的 i,不是共享引用。
- 错误写法(var):所有 setTimeout 都输出 5
- 正确写法(let):输出 0、1、2、3、4
- 注意:let 仅解决 for 循环体内的变量绑定,不解决函数参数或对象属性被意外复用的情况
用立即执行函数(IIFE)手动隔离作用域
ES5 环境或需兼容旧浏览器时,把当前 i 作为参数传入自调用函数,让闭包捕获参数副本。
- 写法:
(function(j) { setTimeout(() => console.log(j), 100); })(i) - 参数名必须和循环变量不同(如 j),避免遮蔽
- 箭头函数不能替代 IIFE,因为它没有自己的作用域
改用数组高阶方法(forEach/map)
forEach、map 的回调函数每次执行都进入新函数作用域,参数天然独立,无需额外处理。
- 示例:
[0,1,2,3,4].forEach(i => setTimeout(() => console.log(i), 100)) - 适用前提:目标是遍历数组;不适用于类数组、for...in 或 for...of
- 本质是靠函数调用栈生成新词法环境,不是语法糖
在循环内显式创建新绑定(Go/Python 思路也适用)
即使语言不支持块级作用域,也可以主动复制变量,切断引用链。
- JS 中:
for (var i = 0; i console.log(cur), 100); } - Go 中:
for _, s := range strs { s := s; go func() { println(s) }() } - 核心逻辑:让闭包捕获的是值的副本,而不是原始变量名的引用











