let 声明循环变量可解决闭包索引错乱问题,因其每次迭代创建独立绑定;var 因函数作用域共享同一 i 导致异步回调全输出最终值;仅 for/for...of/for...in 中 let 声明有效。

用 let 声明循环变量,就能靠块级作用域天然解决闭包中索引错乱的问题——不是靠“复制值”,而是每次迭代都生成一个独立的变量绑定。
为什么 var 在循环里会出问题
var 是函数作用域,整个 for 循环共用同一个 i 变量。异步操作(比如 setTimeout、事件监听、fetch 回调)执行时,循环早已结束,i 已变成最终值(如 5),所有回调读到的都是这个值。
- 所有回调共享同一内存地址上的 i
- 哪怕循环执行了 5 次,i 还是那个 i
- 结果就是:本该输出 0、1、2、3、4,却全输出 5
let 怎么做到每轮循环都有自己的 i
let 的块级作用域机制让 for 循环的每次迭代都创建一个新的词法环境,i 在每轮中其实是不同的绑定(binding),不是拷贝,也不是闭包封装,而是语言层面的独立声明。
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
- for (let i = ...) 中的 i,在每次 i++ 后进入下一轮时,会重新声明一个同名但独立的 i
- 箭头函数或普通函数内部引用的 i,指向的就是当前轮次的那个绑定
- 不需要 IIFE、bind 或额外参数传值,语法简洁且语义清晰
哪些循环结构能自动获得这个效果
只有明确使用 for、for...of、for...in 且变量用 let 声明时,才触发该机制;其他写法不生效。
- ✅
for (let i = 0; i - ✅
for (let item of arr) { ... }—— 每个 item 都是本轮独立绑定 - ❌
let i = 0; while (i console.log(i), 100); i++; }—— i 始终是同一个变量,仍输出 5 个 5
实际开发中的典型场景
除了定时器,这类问题在绑定事件、发起批量请求、生成回调函数时都很常见。
- 菜单项循环绑定 click 事件,想打印对应序号 → 用 let 声明索引或元素
- 遍历按钮数组,为每个按钮设置不同行为 → let 声明循环变量或直接解构
- 循环调用 API,每个请求需携带当前 id → let 声明 id,then 回调里自然捕获正确值
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










