用let声明循环变量可天然获得块级作用域,每次迭代创建独立绑定,避免闭包共享同一变量导致的污染;var则因函数作用域使所有回调输出终值。

用 let 声明循环变量,就能在循环中天然避开闭包导致的变量污染问题。核心不是“配合闭包”,而是 let 自带块级作用域绑定,让每次迭代都拥有独立的变量实例,从而替代了过去靠闭包“模拟隔离”的做法。
let 为什么能解决循环变量污染
var 声明的循环变量属于函数作用域,整个循环共用一个 i,异步回调执行时 i 已变成终值(如 5);而 let 在每次 for 迭代开始时,都会为 i 创建一个新的绑定(binding),每个 setTimeout 回调捕获的是各自迭代那一份 i 的值。
- 不需要手动写 IIFE 封装,代码更简洁、可读性更高
- 不依赖闭包“技巧”,而是由语言机制保障作用域隔离
- 所有现代浏览器和 Node.js 环境(ES6+)均原生支持
典型错误写法与正确写法对比
错误(var + 异步回调):
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100);
}
输出:3、3、3(全部是终值)
当用户要求为 Java 代码添加注释、修改注释、审查注释、整理注释格式,或要求按照代码注释规范处理 Java 文件时,使用本技能。本技能用于统一生成和维护 Java 类注释模板、按 Git 对比 release 判断版本号、补充每行代码上方中文块注释、调整注释空行规则,并保持 Java 文件 UTF-8 无 BOM 编码。典型触发场景包括:补充类注释、更新 @version、检查 @author 来源、整理行尾注释、把注释放到代码上一行、检查注释是否符合规范、构建前检查 Java 注释风格。
立即学习“Java免费学习笔记(深入)”;
正确(let 替代 var):
for (let i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100);
}
输出:0、1、2(各次迭代独立)
注意事项和边界情况
- 必须用 let(或 const)声明循环变量,不能用 var
- 仅适用于 for / for...of / for...in 循环头部声明;在循环体内重新 let 声明同名变量会导致混淆,应避免
- 如果需兼容 IE8–IE10 等极老环境,才需回退到 IIFE 方案,但当前已非常少见
- forEach、map 等数组方法的回调参数本身就在独立作用域内,天然无此问题,也可作为替代方案
它不是闭包,但效果类似
很多人说 “let 实现了自动闭包”,其实不准确。let 绑定是词法环境层面的机制——每次迭代生成新绑定,而非内部函数“捕获外部变量”。它不依赖函数嵌套,也不形成传统意义的闭包结构,但最终达到了相同目的:每个异步操作拿到自己那一份变量值,彻底切断变量泄漏和覆盖风险。

















