let声明的索引变量每次迭代独立绑定,输出0,1,2;var声明共享同一变量,输出3,3,3;const不可用于for循环索引变量。

在 for 循环中定义的索引变量(如 for (let i = 0; i 中的 <code>i),其作用域和内存回收时机由声明方式(let、var 或 const)决定,而非循环结构本身。现代 JavaScript 中推荐使用 let,它带来块级作用域和更可预测的生命周期。
let 声明的索引变量:块级作用域 + 每次迭代独立绑定
let 在 for 循环头部声明时,JavaScript 引擎会在每次迭代开始前为该变量创建一个新的绑定(不是新变量,而是新绑定),因此每个闭包捕获的是各自迭代的值。这避免了经典 var 的“循环绑定问题”。
- 作用域:仅限于 for 语句的整个块(包括小括号内的初始化、条件、更新部分,以及大括号内的循环体)
- 不可重复声明:同一作用域内不能用
let i再次声明 - 不存在变量提升:在声明前访问会报
ReferenceError - 示例:
for (let i = 0; i console.log(i), 0);输出0, 1, 2(各迭代独立绑定)
var 声明的索引变量:函数作用域 + 单一共享绑定
var 声明会被提升到所在函数(或全局)作用域顶部,整个循环共用一个 i 变量。循环结束后,i 仍存在于函数作用域中,值为循环终止时的值(如 n)。
- 作用域:最近的函数作用域(或全局),不是循环块
- 可重复声明:不会报错(但不推荐)
- 存在变量提升:声明被提升,初始化未提升,访问时值为
undefined - 示例:
for (var i = 0; i console.log(i), 0);输出3, 3, 3(共享同一个i)
内存回收时机:取决于变量是否可达,而非循环结束
变量本身不直接“占用内存”,真正占用内存的是它所引用的值(如对象、数组)。索引变量(如数字 i)是原始值,通常存储在栈或寄存器中,开销极小;引擎会在其绑定不可达后尽快回收关联的栈空间。
- 对
let i:每次迭代的绑定在该次迭代结束后即可能变为不可达(尤其当没有闭包引用它时),引擎可在下次垃圾回收周期清理相关栈帧信息 - 对
var i:只要外层函数执行上下文还存在,i就一直可达;函数返回后,整个上下文若不可达,i和其他局部变量才一同被回收 - 注意:V8 等引擎有优化(如“堆栈分配消除”),短生命周期的原始值甚至可能不入堆,也无需 GC 干预
const 用于索引变量?不适用,但可配合解构或固定值
for 循环中不能用 const 声明索引变量(因为每次迭代需重新赋值),但可在循环体内用 const 声明只读的中间值:
- 错误:
for (const i = 0; i → 报错(<code>const不能自增) - 合理:
for (let i = 0; i - 替代方案:优先考虑
for...of或forEach,天然避免手动管理索引















