let 声明循环变量最简洁可靠,因其块级作用域使每次迭代拥有独立绑定;iife、settimeout 第三参数、foreach 等是兼容旧环境的替代方案。

直接用 let 声明循环变量是最简洁、最可靠的解法。它从语言机制上杜绝了共享绑定问题,不需要额外封装或传参,现代浏览器和 Node.js 环境已全面支持。
用 let 替代 var,让每次迭代拥有独立绑定
var 声明的变量是函数作用域,整个 for 循环共用一个 i;而 let 是块级作用域,每次迭代都会创建一个新的绑定,闭包捕获的是各自独立的 i。
- ✅ 正确写法:
for (let i = 0; i console.log(i), 1000); }→ 输出 0、1、2、3、4 - ❌ 错误写法:
for (var i = 0; i console.log(i), 1000); }→ 输出 5 个 5
用立即执行函数(IIFE)手动创建作用域(兼容旧环境)
在必须支持 ES5 的场景下,可通过 IIFE 把当前 i 值作为参数传入,使内部函数闭包捕获的是形参副本,而非外部变量引用。
- 写法示例:
for (var i = 0; i console.log(j), 1000); })(i); } - 注意:箭头函数不能替代 function 声明——只有 function 才能形成新作用域;参数名(如 j)需与循环变量名不同,避免遮蔽
利用 setTimeout 的第三个参数传值(轻量且语义清晰)
setTimeout 支持在延迟执行函数之后追加任意数量参数,这些参数会原样传递给回调函数,相当于隐式绑定当前值。
- 写法示例:
for (var i = 0; i console.log(j), 1000, i); } - 优势:无需额外函数包裹,逻辑直白,适用于所有支持该 API 的运行时(包括较老版本浏览器)
改用数组高阶方法(forEach/map),天然隔离索引
forEach、map 等方法的回调函数每次调用都处于全新函数作用域,参数是独立传入的值,不存在变量复用问题。
- 适用前提:目标是遍历真实数组(非类数组或 NodeList)
- 示例:
[0,1,2,3,4].forEach((num, i) => setTimeout(() => console.log(i), 1000 * i)); - 注意:for...of 或 for in 不具备此特性,仍需配合 let 使用










