在 JavaScript 中,const、let 和 var 都用于声明变量,但它们有以下主要区别:
1. 作用域 (Scope)
- var: 函数作用域 (function-scoped)
- let/const: 块级作用域 (block-scoped)
if (true) {
var a = 1;
let b = 2;
const c = 3;
}
console.log(a); // 1 (可以访问)
console.log(b); // ReferenceError
console.log(c); // ReferenceError
2. 变量提升 (Hoisting)
- var: 声明会被提升到作用域顶部,初始值为
undefined - let/const: 声明也会提升,但不会被初始化(暂时性死区)
console.log(x); // undefined
var x = 5;
console.log(y); // ReferenceError
let y = 5;
3. 重复声明
- var: 允许在同一作用域内重复声明
- let/const: 不允许在同一作用域内重复声明
var a = 1;
var a = 2; // 允许
let b = 1;
let b = 2; // SyntaxError
const c = 1;
const c = 2; // SyntaxError
4. 值的修改
- var/let: 声明的变量可以重新赋值
- const: 声明的是常量,不能重新赋值(但对象/数组的内容可以修改)
var a = 1;
a = 2; // 允许
let b = 1;
b = 2; // 允许
const c = 1;
c = 2; // TypeError
const obj = {x: 1};
obj.x = 2; // 允许(修改对象属性)
5. 全局对象属性
- var: 在全局作用域中声明会成为全局对象(浏览器中是
window)的属性 - let/const: 不会成为全局对象的属性
var a = 1;
console.log(window.a); // 1 (浏览器环境)
let b = 2;
console.log(window.b); // undefined
最佳实践
- 默认使用
const(除非需要重新赋值) - 需要重新赋值时使用
let - 避免使用
var(除非有特殊需求)
这种使用顺序可以帮助减少意外的变量修改和提高代码可读性。
const 可以被修改?
当你执行以下代码时:
const a = [];
a.push(1);
console.log(a); // 输出 [1]
为什么可以修改?
虽然 const 声明的变量不能被重新赋值,但对于引用类型(如数组、对象)来说,const 只是保证变量名指向的内存地址不变,而不是保证该内存地址中的内容不变。
-
不可重新赋值:你不能给
a赋一个新数组或新值const a = []; a = [1, 2, 3]; // 报错:Assignment to constant variable -
可以修改内容:但可以修改数组/对象本身的内容
const a = []; a.push(1); // 允许 a[0] = 2; // 允许
内存模型解释
a → [内存地址A] → 实际数组内容
const 只保证 a 永远指向 [内存地址A],但不限制 [内存地址A] 中的内容变化。
如果要完全不可变
可以使用 Object.freeze():
const a = Object.freeze([]);
a.push(1); // 在严格模式下会报错
最佳实践
- 用
const声明所有不需要重新赋值的变量 - 如果确实需要完全不可变的数据结构,考虑使用 Immutable.js 等库