答案是var与let的作用域差异导致闭包捕获行为不同:var为函数作用域,循环共用一个i,settimeout回调执行时i已变为终值;let为块级作用域,每次迭代创建独立i,闭包正确捕获对应值。

这类题目核心不是考你背答案,而是看你是否理解变量作用域、执行时机和闭包的本质。输出结果差异,基本都来自 var 和 let 的作用域区别,以及 定时器回调执行时能否“捕获”当时的循环变量值。
为什么 var 循环 + setTimeout 总是输出最后的值?
因为 var 声明的变量是函数作用域(或全局),整个 for 循环共用一个 i。循环很快跑完,i 最终变成 5(比如 i
- 循环体内部没有形成独立作用域,i 不是“每次循环一份”
- 定时器回调是异步任务,压入任务队列时,同步代码(包括整个 for)早已结束
- 所有回调共享外层作用域中的那个 i 变量
怎么让每个定时器输出对应的 i 值?
关键在于:让每个回调“记住”自己那一轮的 i。常用两种方式:
- 用 let 声明循环变量:let 是块级作用域,每次迭代都会创建一个新的 i 绑定,回调访问的是各自独立的那份 i
- 用立即执行函数(IIFE)包裹:把当前 i 作为参数传进去,在函数内部形成闭包,把值“锁住”
例如:for (let i = 0; i console.log(i), 0); } 输出 0、1、2;而 for (var i = 0; i console.log(i), 0); })(i); } 同样输出 0、1、2。
一款AI办公效率工具,主要用于适用于兼容 Agent Skills 产品的通用(非 OpenClaw)Nutrient DWS 文档处理技能。最佳搭配:Claude Code、Codex CLI、Gemini CLI、Cursor、Wi...,适合需要提升相关任务效率的用户。
setTimeout 和 setInterval 在闭包题里有什么不同?
区别主要在执行节奏和清理逻辑上:
- setTimeout 是单次延迟执行,适合模拟“按序触发”,但要注意清除时机(比如 clearTimeout 传错 id 就清不掉)
- setInterval 是重复执行,容易出现“多个定时器同时跑”或“清除不及时导致重复打印”,尤其当传参不当时(如把 tc 当参数传进回调却没正确绑定)
- 常见陷阱:在 setInterval 回调里直接用外部声明的 tc,结果所有回调都清除的是最后一次赋值的 tc,导致只停掉最后一个
面试官想看什么?
不只是写出正确代码,更希望你讲清楚:
- 为什么原代码出错(作用域 + 执行时机)
- let 和 IIFE 分别解决了什么问题(块级绑定 vs 闭包捕获)
- 能不能举一反三,比如换成 Promise 或 async/await 是否还有同样问题
- 是否意识到过度使用闭包可能带来的内存隐患










