`const`, `let`, `var` 的区别

266 阅读2分钟

在 JavaScript 中,constletvar 都用于声明变量,但它们有以下主要区别:

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

最佳实践

  1. 默认使用 const(除非需要重新赋值)
  2. 需要重新赋值时使用 let
  3. 避免使用 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 等库