1. const 在循环中的基本行为
const 是一种块级绑定的声明方式,在循环结构中也遵循这一规则。当你在循环内部使用 const 声明一个变量时,每次迭代都会产生一个独立的绑定实例,这个绑定在当前代码块内是不可重新赋值的。
在实际编程中,每次迭代都拥有独立的绑定是避免常见闭包陷阱的关键所在。比如在遍历数组并把每个元素传递给异步回调时,使用 for...of 搭配 const 可以确保回调看到的是该次迭代的实际值,而不是循环结束后才确定的最终值。
// 仅作演示:每次迭代都与当前 item 绑定,回调中输出正确的 item
const items = [{id:1},{id:2},{id:3}];
for (const item of items) {setTimeout(() => console.log(item.id), 0);
}如果你尝试用不正确的模式,例如在循环头直接用 const 并进行修改,将会立即抛出错误,因为 常量绑定不可重新赋值。这也是为什么一些“看起来像循环赋值”的写法会在运行时失败的原因之一。
// 错误示例:尝试在循环中修改常量会报错
for (const i = 0; i < 3; i++) {// Uncaught TypeError: Assignment to constant variable.
}1.1 块级作用域与 TDZ 在循环中的体现
在循环局部,块级作用域确保了循环内部的绑定与外部作用域互不干扰。与此同时,暂时性死区(TDZ)保证了在当前块未初始化前不能使用该变量,从而避免了早期赋值导致的错误。
下面的示例展示了在循环体内正确使用 let/const 的绑定方式,并强调每次迭代的绑定独立性。
const items = [10, 20, 30];
for (const v of items) {// 每次迭代 v 都是新的绑定,且不可重新赋值console.log(v);
}1.2 用 const 声明的正确场景和限制
一般而言,在需要依赖当前迭代值并且不希望被重新赋值时,使用 for...of + const 是最直观的组合。它确保了每次迭代的值不会在循环体内被意外修改,也避免了悬垂引用的问题。
如果你需要在循环中对中间变量进行修改,应该使用 let,而不是 const,以避免让绑定失去原本的不可变特性。
const data = [{x:1},{x:2}];
for (let i = 0; i < data.length; i++) {// 需要在循环中改变的量使用 letlet current = data[i].x;current += 1;console.log(current);
}2. const 在不同循环结构中的行为差异
2.1 for...of 与 for 循环中的新绑定
在现代 JavaScript 中,for...of 和很多循环结构对 const 的处理使得每次迭代都会生成一个新的绑定。这意味着闭包里引用的值不会随循环结束而改变,从而避免了常见的“循环变量最终值被捕获”的问题。
示例一:在 setTimeout 回调中使用 const,确保输出的是当前迭代的 item。
const arr = ['a','b','c'];
for (const ch of arr) {setTimeout(() => console.log(ch), 0);
}示例二:若改用 var,回调里看到的往往是循环结束后的最后一个值,这就是传统闭包问题的典型表现。
// 使用 var 会导致闭包捕获最终值
for (var i = 0; i < arr.length; i++) {setTimeout(function() { console.log(i); }, 0);
}2.2 与普通 for 循环的对比
普通的 for 循环里,若使用 let 声明迭代变量,同样会在每次迭代中生成新的绑定,但若使用 var,则仍然是同一个绑定,值会被逐步改变。这也是理解“同一绑定 vs 新绑定”的关键点。
const arr = [1,2,3];
for (let i = 0; i < arr.length; i++) {// i 在每次迭代中都是新的绑定console.log(i);
}
for (var j = 0; j < arr.length; j++) {// j 是同一个绑定,循环结束后会是最后的值console.log(j);
}3. 常见误解与要点
3.1 不是所有循环都能用 const
并非所有循环场景都适合在循环中使用 const。当你需要在循环内改变变量值,或在同一作用域内重复重新赋值时,应选择 let 或 var,而不是强行把其设为 const。
下列场景中,使用 const 仍然可靠:在循环中声明一个不可变的引用指向每次迭代的对象,或在 for...of 的迭代中直接绑定当前项,并在回调中保持不变。
const items = [{id: 1}, {id: 2}];
for (const item of items) {// item 每次都是一个新的绑定,且不可重新赋值console.log(item.id);
}3.2 对异步回调的影响
在涉及异步操作(如 setTimeout、Promise 等)的场景中,const 的使用能够确保回调看到的是当前迭代的具体值,从而避免输出混乱或错位的情况。

const tasks = [];
for (const item of items) {tasks.push(() => console.log(item.id));
}
tasks.forEach(t => t());4. 实战示例:在数组遍历中安全使用 const
4.1 使用 for...of 与 const 的组合
在需要把遍历结果交给异步任务或后续操作时,for...of + const 的组合能够确保每次迭代的值被独立绑定,不会随循环结束而被污染。
const list = [{id: 101}, {id: 102}, {id: 103}];
for (const item of list) {setTimeout(() => console.log(item.id), 0);
}在这里,每次输出的 id 都与对应的 item 一一对应,这正是 const 在循环中的应用揭秘 的核心体现之一。
4.2 结合 IIFE 的历史做法与对比
在早期没有 let/const 的浏览器中,常用 IIFE 来锁定循环中的变量值,以避免闭包问题。虽然现在有了更简洁的语法,但理解 IIFE 的思想有助于理解绑定的作用域边界。
// 旧方法:使用 IIFE 锁定变量
for (var i = 0; i < items.length; i++) {(function(cur) {setTimeout(function() { console.log(cur.id); }, 0);})(items[i]);
} 

