`var`、`let`、`const`三部曲

48 阅读4分钟

 JavaScript 变量声明三巨头:varletconst 彻底搞懂

标签:#JavaScript #前端 #变量声明 #作用域 #暂时性死区

在 JavaScript 中,变量声明看似简单,但 varletconst 的行为却大不相同。很多初学者甚至工作多年的开发者,都曾被它们的“变量提升”、“暂时性死区”、“作用域”等问题困扰。

今天,我们就来彻底搞懂这三种变量声明方式的区别,帮你避开常见坑点,写出更安全、可维护的代码。


一、JavaScript 中如何声明变量?

在 JS 中,我们有三种方式声明变量:

js
编辑
var name = "张三";
let age = 20;
const PI = 3.14;

虽然都能“声明变量”,但它们的作用域、提升行为、可修改性完全不同。


二、var:被时代淘汰的“老将”

✅ 基本用法

js
编辑
var a = 1;

❌ 三大“反直觉”问题

1. 变量提升(Hoisting)

var 声明的变量会被“提升”到作用域顶部。

js
编辑
console.log(a); // undefined,而不是报错
var a = 1;

👉 原理:在编译阶段,JS 引擎会把 var a; 提升到顶部,但赋值留在原地。

js
编辑
// 实际执行顺序
var a;
console.log(a); // undefined
a = 1;

2. 函数作用域(Function Scope)

var 只有函数作用域,没有块级作用域。

js
编辑
{
    var age = 18;
}
console.log(age); // 18!可以访问

👉 即使在 {} 块中声明,var 也会“逃逸”到外层作用域。

3. 可重复声明

js
编辑
var name = "张三";
var name = "李四"; // 不报错!

👉 这容易导致变量覆盖,引发 bug。


三、let:现代 JS 的推荐选择

✅ 基本用法

js
编辑
let name = "张三";

✅ 核心特性

1. 块级作用域(Block Scope)

js
编辑
{
    let age = 18;
}
console.log(age); // ❌ 报错:ReferenceError: age is not defined

👉 let 只在 {} 块内有效,出了块就“消失”。

2. 暂时性死区(Temporal Dead Zone, TDZ)

在声明之前访问 let 变量会报错!

js
编辑
console.log(name); // ❌ 报错:Cannot access 'name' before initialization
let name = "张三";

👉 这比 varundefined 更安全,避免了“静默错误”。

3. 不可重复声明

js
编辑
let name = "张三";
let name = "李四"; // ❌ 报错:Identifier 'name' has already been declared

四、const:常量声明,但不是“不可变”

✅ 基本用法

js
编辑
const PI = 3.14;

✅ 核心规则

const 只保证“指向不变”,不保证“内容不变”

1. 基本类型:不能修改

js
编辑
const age = 18;
age = 20; // ❌ 报错:Assignment to constant variable.

2. 对象/数组:可以修改内容

js
编辑
const person = {
    name: "张三",
    age: 18
};

person.age = 20;        // ✅ 合法
person.name = "李四";   // ✅ 合法

person = {};            // ❌ 报错:不能重新赋值

🔥 重点const 锁的是“变量的指向”,而不是“对象的内容”。

3. 如何让对象真正不可变?

使用 Object.freeze()

js
编辑
const frozenPerson = Object.freeze({
    name: "张三",
    age: 18
});

frozenPerson.age = 20; // ❌ 静默失败(严格模式下报错)

Object.freeze():可以冻结对象,使其真正不可变


五、常见报错解析

❌ ReferenceError: height is not defined

  • 原因:变量未声明,或在作用域外访问。

  • 示例

    js
    编辑
    {
        let height = 180;
    }
    console.log(height); // 报错
    

❌ TypeError: Assignment to constant variable.

  • 原因:试图给 const 变量重新赋值。

  • 示例

    js
    编辑
    const name = "张三";
    name = "李四"; // 报错
    

❌ ReferenceError: Cannot access 'PI' before initialization

  • 原因:在 let 或 const 声明前访问,处于“暂时性死区”。

  • 示例

    js
    编辑
    console.log(PI);
    const PI = 3.14; // 报错
    

六、最佳实践建议

场景推荐写法
声明变量优先使用 let
声明常量(如配置、数学常数)使用 const
避免 var除非兼容老环境
修改对象用 ... 扩展运算符创建新对象,避免直接修改
数组操作用 mapfilter 等函数式方法,避免 push 直接修改

✅ 推荐代码风格

js
编辑
// ✅ 好的写法
const API_URL = "https://api.example.com";
let userCount = 0;

function updateUser() {
    userCount += 1;
    const newUser = { ...user, lastLogin: Date.now() };
    return newUser;
}

七、总结对比表

特性varletconst
作用域函数作用域块级作用域块级作用域
变量提升✅(值为 undefined✅(但有 TDZ)✅(但有 TDZ)
暂时性死区
可重复声明
可重新赋值
推荐使用

✅ 结语

  • var 是“历史遗留”,行为反直觉,不推荐使用
  • let 是“现代标准”,块级作用域,安全可靠,推荐用于变量声明
  • const 是“最佳实践”,明确表示“不可重新赋值”,推荐用于常量和对象声明

记住一句话
const 优先,let 次之,var 不用。

掌握这三者的区别,不仅能避免常见 bug,还能写出更清晰、可维护的代码。