JavaScript 中 var、let、const 的核心区别与 2025–2026 年实战应用指南
即使到了 2026 年,这三个关键字的区别仍然是面试、代码审查、团队规范中最常被讨论的基础点之一。下面用最清晰的对比 + 真实场景 + 现代最佳实践给你讲透。
1. 一张表看清核心区别(2026 年共识版)
| 特性 | var | let | const |
|---|---|---|---|
| 作用域 | 函数作用域(function scope) | 块级作用域(block scope) | 块级作用域(block scope) |
| 变量提升(Hoisting) | 提升并初始化为 undefined | 提升但有 TDZ(Temporal Dead Zone) | 提升但有 TDZ |
| 能否重复声明(同一作用域) | 可以 | 不可以 | 不可以 |
| 能否重新赋值 | 可以 | 可以 | 不可以(但对象/数组内容可变) |
| 声明前使用 | 可以(值为 undefined) | 报错(ReferenceError) | 报错(ReferenceError) |
| 全局对象属性(浏览器) | 是(挂到 window) | 否 | 否 |
| 现代推荐度(2025-2026) | ★☆☆☆☆(基本禁用) | ★★★★☆(需要重新赋值时用) | ★★★★★(默认首选) |
2. 最容易踩的坑对比(带代码)
// 1. 块级作用域差异(for 循环经典案例)
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 0); // 3 3 3
}
for (let j = 0; j < 3; j++) {
setTimeout(() => console.log(j), 0); // 0 1 2
}
// 2. TDZ(Temporal Dead Zone) — 非常高频面试题
console.log(a); // undefined
var a = 1;
console.log(b); // ReferenceError: Cannot access 'b' before initialization
let b = 2;
console.log(c); // ReferenceError
const c = 3;
// 3. const 真正不可变的只有“引用”,内容可变
const user = { name: "Alice" };
user.name = "Bob"; // ✅ 合法
user = { name: "Charlie" }; // ❌ TypeError: Assignment to constant variable
const arr = [1, 2, 3];
arr.push(4); // ✅ 合法
arr = [5, 6]; // ❌ TypeError
3. 2025–2026 真实项目中的使用规律(现代最佳实践)
| 场景 | 推荐写法 | 理由 / 说明 |
|---|---|---|
| 常量、配置、魔法数字、React key | const | 防止意外修改,提高可读性 |
| React useState 初始值、循环累加器 | const | 绝大多数情况下你不会重新绑定整个变量,只 mutate 内容 |
| for/of 循环的计数器、while 条件变量 | let | 需要重新赋值 |
| 需要在块内临时变量(if/switch 内) | let / const | 利用块级作用域自动销毁,避免变量泄漏 |
| 闭包中需要捕获变化的值 | let | var 会捕获最后的值,let 每次循环创建新绑定 |
| 导出模块的常量 | const | export const API_URL = “…”; |
| 老项目维护 / IE11 兼容代码 | var | 极少数情况(现在基本用 babel/ts 处理兼容) |
| 全局变量(极少用) | const / let | 避免挂到 window,推荐用模块化 + import |
2026 年最主流团队规范(几乎所有中大型项目都这样写):
1. 默认使用 const
2. 只有明确需要重新赋值时才改用 let
3. 永远不要再写 var(除非你在修 10 年前的遗留代码)
4. 高频真实业务代码对比(让你立刻感受到差距)
反例(容易出 bug 的 var 风格)
function processUsers(users) {
var result = [];
var i; // 容易无意提升
for (i = 0; i < users.length; i++) {
var user = users[i]; // 整个函数都能访问到最后一个 user
// ...
}
console.log(user); // 最后一个用户,可能是意外的
}
现代推荐写法
function processUsers(users) {
const result = [];
for (let i = 0; i < users.length; i++) {
const user = users[i]; // 只在本次循环有效
// ...
}
// console.log(user); ← 这里会报错,很好!避免了隐藏 bug
}
更现代(for…of + const)
function processUsers(users) {
const result = [];
for (const user of users) { // 最清晰、最安全
// user 每次都是新的 const 绑定
result.push(user.name.toUpperCase());
}
return result;
}
5. 快速决策口诀(背下来,终身受益)
- 不知道用哪个 → 写 const
- 发现要改值 → 改成 let
- 看到 var → 想办法重构掉(除非是必须兼容 2009 年的代码)
一句话总结(2026 年真实写法心态):
“const 是默认,let 是例外,var 是历史遗留。”
你现在遇到具体哪种场景纠结用哪个?
比如 React Hooks 里、循环里、Promise 链里、还是 TypeScript + const enum 相关?
告诉我,我可以直接给对应场景的最优写法。