let 声明通过为每次循环迭代创建独立绑定,解决 var 因函数作用域和变量提升导致的异步回调共享同一变量值问题;for (var i...) 输出 3,3,3,而 for (let i...) 正确输出 0,1,2。

let 声明通过块级作用域,让每次循环迭代都创建独立的变量绑定,从而天然解决异步循环中 var 声明导致的“所有回调共享同一个变量”的问题。
为什么 var 在循环中会出问题
使用 var 声明的变量具有函数作用域,且存在变量提升。在 for 循环中,var 变量在整个函数内只有一份,所有异步回调(如 setTimeout、Promise.then)引用的都是这个变量的最终值。
例如:
for (var i = 0; i setTimeout(() => console.log(i), 100);}
输出是 3, 3, 3 —— 因为循环结束时 i 已变为 3,而所有回调执行时访问的是同一个 i。
立即学习“Java免费学习笔记(深入)”;
let 如何修复这个问题
let 为每次循环迭代创建一个新的绑定(binding),每个回调捕获的是该次迭代独有的 i 值。
改用 let 后:
在调试 Java 后端 API 故障时使用此技能,尤其适用于以下任务:分析日志、跨 Controller、Service 和 Mapper 层追踪请求、定位异常根因、检查 SQL 执行或参数流转,以及生成简洁的诊断结论与修复方案。
}
输出是 0, 1, 2 —— 每个 setTimeout 拿到的是各自迭代时的 i。
这是因为 ES6 规范明确要求:for 循环中每次迭代都会为 let/const 声明的变量创建新绑定,而非复用旧变量。
适用场景不止于 setTimeout
let 的块级绑定对各类异步操作都有效,包括:
- Promise 链中的 .then 回调
- fetch 或 axios 请求的响应处理
- 事件监听器(如在循环中为多个按钮添加 click 处理函数)
- async/await 中 await 后的代码(只要变量在循环块内声明)
关键点:变量必须用 let 声明在 for 循环头部(for (let i...)),而不是在循环体内重复 let —— 后者虽不报错,但逻辑上可能偏离预期。
注意边界情况
let 的修复能力有前提:
- 必须是标准 for、for...of、for...in 循环;while 或 do...while 不自动创建每次迭代的新绑定(需手动用 {} 块或立即执行函数)
- 如果在循环内用 var 声明新变量,它仍会受函数作用域影响
- 箭头函数或普通函数需真正“闭包”住该次迭代的 let 变量——这通常默认成立,但若把变量传给外部未绑定上下文的函数,仍可能丢失
简单说:用 for (let x of arr) + 异步操作,基本不会踩坑。

















