let为每次循环迭代创建独立绑定,解决var共享变量导致的闭包问题;var因函数作用域和变量提升,所有回调访问同一最终值,而let确保每个回调捕获各自迭代的i值。

用 let 声明循环变量,就能自然解决 for 循环中因 var 声明导致的闭包问题——因为 let 为每次迭代创建独立的块级作用域绑定。
为什么 var 会出问题
var 声明的变量具有函数作用域且存在变量提升,整个 for 循环共享同一个 i 变量。当异步操作(如 setTimeout)在循环结束后才执行时,所有回调访问的都是最终的 i 值(比如 5)。
例如:
for (var i = 0; i setTimeout(() => console.log(i), 100);}
输出:5 5 5 5 5
let 是怎么解决的
let 声明的变量具有块级作用域,并且在 for 循环每次迭代中,JavaScript 引擎会为该次迭代的 i 创建一个**新的绑定**(不是拷贝值,而是新绑定),因此每个 setTimeout 回调捕获的是各自迭代时的 i 值。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
改写后:
for (let i = 0; i setTimeout(() => console.log(i), 100);}
输出:0 1 2 3 4
关键细节要注意
- 必须是 for (let i...) {...} 这种直接声明在 for 语句中的写法,let 才会在每次迭代初始化新绑定
- 如果写成 let i; for (i = 0; ...),效果等同于 var —— 失去块级迭代绑定特性
- 箭头函数或普通函数均可,关键是 i 的绑定时机,不是函数类型
- 该机制是 ES6 规范明确规定的(称为“per-iteration binding”),不是浏览器实现差异
其他可行方案对比
虽然 let 是最简洁直接的解法,但也可通过以下方式绕过:
- 立即执行函数(IIFE) + var:把 i 作为参数传入,形成闭包作用域
- setTimeout 第三个参数传参:setTimeout(fn, delay, arg) 把 i 当作参数传给回调
- for...of 配合 const:遍历数组时可用 const,但不适用于纯数字计数场景
不过这些都属于“补救”,而 let 是从根源上让语法行为符合直觉。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










