使用var声明for循环变量会导致所有闭包共享同一i,异步执行时统一输出终值(如3),根本原因是var是函数作用域且闭包捕获变量引用而非值。
var 声明变量会出什么问题所有闭包共享同一个 i 变量,循环结束时 i 已是终值(比如 3),所以 setTimeout、事件回调或函数数组里调用时全输出 3。
根本原因是:var 是函数作用域,整个循环体共用一个 i 绑定;闭包捕获的是变量引用,不是当时值。
console.log(i) 在异步回调中统一输出最终值for range 的变量复用陷阱Go 的循环变量(如 i 或 s)在每次迭代中**不新建内存地址**,只是更新值。所有闭包(包括 go func() { ... }())都指向同一块内存,导致全部读到循环末尾的值。
例如:for _, s := range []string{"a", "b", "c"} { funcs = append(funcs, func() { println(s) }) } 会输出三个 c。
let 那套不适用s := s,强制创建新绑定go func(s string) { println(s) }(s) 也行,但短变量声明更简洁forEach 和 map 能绕过这个问题因为它们的回调函数每次执行都进入一个新函数作用域,参数是每次传入的独立值,天然隔离。
比如:[0,1,2].forEach(i => setTimeout(() => console.log(i), 100)) 输出就是 0、1、2。
for in 场景;也不能解决 for of 或原生 for 的问题本质是手动造一个新作用域,把当前循环变量作为参数传进去,让闭包捕获的是参数副本。
写法:(function(j) { setTimeout(() => console.log(j), 100); })(i)。
function 声明,箭头函数无法形成独立作用域j)要和循环变量名不同,避免遮蔽