闭包在定时器循环中确保每个回调捕获各自迭代时的变量值,解决var声明下settimeout输出同一终值的问题;let声明或iife可创建独立作用域,使每次回调引用不同的i值。

闭包在定时器循环执行中,核心作用是让每个回调“记住”它创建时的变量值,而不是等到执行时再去读取——这直接解决了 for 循环中 setTimeout 输出全是最后一个值的经典问题。
为什么循环里的 setTimeout 总输出同一个数?
根本原因在于作用域和变量绑定方式:
-
var声明没有块级作用域,整个循环共用一个i变量 - 循环很快结束,
i最终变成终值(比如 3) - 而
setTimeout是异步延迟执行,等它真正运行时,i早已固定为那个终值 - 所有回调函数通过闭包访问的,其实是同一份内存地址上的
i
闭包如何帮我们拿到正确的值?
关键是为每次迭代创建独立的作用域,让每个回调捕获各自那一份 i:
-
用
let替代var:ES6 的let在每次循环迭代中生成新的绑定,每个setTimeout回调闭包引用的是不同轮次的i -
用 IIFE(立即执行函数)传参:把当前
i作为参数传入,形成局部变量供内部回调使用 -
封装成带参函数再调用:把
setTimeout逻辑抽离为接收i的函数,调用时实参即刻绑定
实际写法对比
错误写法(输出 3, 3, 3):
Java开发手册规约集合,基于阿里巴巴Java开发手册(嵩山版)。 涵盖7大维度:编程规约、异常日志、单元测试、安全规约、MySQL数据库、工程结构、设计规约。 当用户需要:(1) 编写或审查Java代码 (2) 检查命名/代码规范 (3) 处理异常和日志 (4) 编写单元测试 (5) 安全编码 (6) 数据库设...
推荐写法(输出 0, 1, 2):
for (let i = 0; i console.log(i), 100); }或 IIFE 写法:
for (var i = 0; i console.log(j), 100); })(i); }闭包在这里不只是技巧,而是机制刚需
它不是可有可无的优化,而是 JavaScript 执行模型下的必然需求:
- 定时器回调被推入任务队列时,外层函数早已执行完毕
- 没有闭包,回调就无法访问到循环当时的
i值 - 闭包提供了词法环境的“快照”能力,让变量在函数退出后仍可被安全引用
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










