深入解析 JavaScript 中 var、let 与 const 的核心差异

作者:小括号

时间:2026-10-24

浏览:489

本文全面解析 JavaScript 中 var、let 和 const 三种变量声明方式的区别。重点阐述作用域(函数级与块级)、变量提升机制、暂时性死区以及 const 的引用限制。结合经典面试题,分析 for 循环中的变量行为,并提供现代 JS 开发中优先使用 const 的最佳实践建议。

文章目录

引言

针对 var、let 与 const 三个关键字的差异,这是一个频繁出现的经典面试话题。本文深入解析三者的特性及区别,由浅入深帮助你彻底掌握该知识点。

变量声明机制

ECMAScript 中的变量属于松散类型,即变量可存储任意类型的数据,每个变量仅作为保存任意值的命名占位符。

存在三个声明变量的关键字:var、let 和 const。其中 var 兼容 ECMAScript 所有版本,而 let 和 const 仅支持 ES6 及更高版本。

var 关键字

使用 var 操作符(注意 var 为关键字)后接变量名(标识符)来定义变量:

var message;

上述代码定义了一个名为 message 的变量,可存储任意类型的值。若未初始化,该变量将保存特殊值 undefined。

ECMAScript 支持变量初始化,因此可同步定义变量并赋予初始值:

var messgae = "hi";

message 被定义为存储字符串值 "hi" 的变量。此类初始化仅为简单赋值,并未将变量标识为字符串类型。后续既可修改保存的值,也可改变值的类型:

var message = "hi";
message = 666; // 合法,但不推荐
console.log(message); // 666

若需定义多个变量,可在单条语句中用逗号分隔每个变量(及可选的初始化操作):

var message,
    name = "孙悟空",
    age = 18;

作用域规则

使用 var 定义的变量将成为其所在函数的局部变量。例如,在函数内部使用 var 定义的变量,将在函数执行结束时被销毁:

function test() {
    var message = "hi"; // 局部变量
}
test();
console.log(message); // error: message is not defined

若在函数内部定义变量时省略 var 操作符,则会创建一个全局变量:

function test() {
    message = "hi"; // 全局变量
}
test();
console.log(message); // ok

尽管可通过省略 var 操作符定义全局变量,但强烈不推荐此做法。在严格模式下,对未声明的变量赋值将引发错误。

在同一作用域内,多次使用 var 声明同一变量是允许的:

function test() {
    var message = "hi";
    var message = false;
    var message = 666;

    console.log(message); 
}
test(); // 666

变量提升机制

所谓提升,是指将所有变量声明移至函数作用域的顶部。需注意,仅提升声明部分,不提升赋值操作。

示例如下:

function test() {
    console.log(message);
    var message = "hi";
}
test(); // undefined

上述代码不会报错,因为使用 var 关键字声明的变量会提升至函数作用域顶部,其效果等同于以下代码:

function test() {
    var message;
    console.log(message);
    message = "hi";
}
test(); // undefined

let 关键字

let 与 var 的作用相似,但存在关键区别。

作用域差异

var 声明的范围是函数作用域,而 let 声明的范围是块作用域:

if (true) {
    var message = "hi";
    console.log(message); // hi
}
console.log(message); // hi


if (true) {
    let message = "hi";
    console.log(message); // hi
}
console.log(message); // error: message is not defined

message 变量之所以无法在 if 块外部引用,是因为其作用域仅限于该块内部。块作用域是函数作用域的子集,因此适用于 var 的作用域限制同样适用于 let。

let 不允许在同一块作用域内进行冗余声明:

if (true) { 
    // error: 无法重新声明块范围变量“a”
    let a;
    let a;
}

JS 引擎会记录变量声明的标识符及其所在的块作用域,因此嵌套使用相同标识符不会报错,因为同一块内不存在重复声明:

let a = 666;
console.log(a); // 666
if (true) {
    let a = '啊哈哈';
    console.log(a); // 啊哈哈
}

var 和 let 声明的并非不同类型的变量,它们仅指示变量在相关作用域中的存在方式,因此对声明冗余的错误检查不会因混用 var 和 let 而受影响:

// error
var a;
let a;

// error
let b;
var b;

暂时性死区(TDZ)

let 声明的变量不会在作用域中被提升:

if (true) {
    console.log(x); // error: 在赋值前使用了变量“x”
    let x = 520;
}

在解析代码时,JS 引擎会注意出现在块后面的 let 声明,只不过在此之前不能以任何方式引用未声明的变量。在 let 声明之前的执行瞬间被称为暂时性死区,在此阶段引用任何后续才声明的变量都会报错。

const 关键字

const 的行为与 let 基本相同,唯一重要区别在于:使用 const 声明变量时必须同时初始化变量,且尝试修改 const 声明的变量会导致运行时报错:

const a; // error: 必须初始化 "const" 声明

const b = 250;
b = 520; // error: 无法赋值给 "b" ,因为它是常数

需注意,const 声明的限制仅适用于其指向的变量引用。换言之,若 const 变量引用的是一个对象,修改该对象内部的属性并不违反 const 限制:

const obj = { x: 666 };
obj.x = 888; // ok
obj.y = '啊哈哈'; // ok

扩展知识

全局声明行为

使用 var 在全局作用域中声明的变量会成为 window 对象的属性,而 let 和 const 声明的变量则不会:

var a = 666;
console.log(window.a); // 666

let b = 666;
console.log(window.b); // undefined

const c = 666;
console.log(window.c); // undefined

for 循环中的 let 声明

首先看一个例子:

for (var i = 0; i < 5; i++) {
    ...
}
console.log(i);

思考一下,打印结果会是什么?

由于 var 声明的变量不具备块作用域,迭代变量 i 会渗透到循环体外部。当 i 递增到 5 时退出循环,打印结果为 5。

若使用 let 声明迭代变量,即可将迭代变量的作用域限制为 for 循环块内部:

for (let i = 0; i < 5; i++) {
    ...
}
console.log(i); // error: i is not defined

再看一个例子:

for (var i = 0; i < 5; i++) {
    setTimeout( () => {
        console.log(i);
    }, 0 )
}

你可能预期输出:0、1、2、3、4,实际上输出的是:5、5、5、5、5。

产生该结果的原因是,在退出循环时,迭代变量保存的是导致循环退出的值,即 5。在之后异步执行超时逻辑时,所有的 i 都是同一个变量,因此输出的都是同一个最终值。

而在使用 let 声明迭代变量时,JS 引擎在后台会为每个迭代循环声明一个新的迭代变量。每个 setTimeout 引用的都是不同的变量实例,所以 console.log 输出的是我们期望的值,即循环执行过程中每个迭代变量的值:

for (let i = 0; i < 5; i++) {
    setTimeout( () => {
        console.log(i); // 0、1、2、3、4
    }, 0 )
}

这是一道经典面试题,若不太理解请务必反复阅读,最好动手实践,直至彻底搞懂。

总结

  • var 声明的范围是函数作用域,let 和 const 声明的范围是块作用域

  • var 声明的变量会被提升至函数作用域的顶部,let 和 const 声明的变量不存在提升,且具有暂时性死区特征

  • var 允许在同一个作用域中重复声明同一个变量,let 和 const 不允许

  • 在全局作用域中使用 var 声明的变量会成为 window 对象的属性,let 和 const 声明的变量则不会

  • const 的行为与 let 基本相同,唯一重要区别是,使用 const 声明的变量必须进行初始化,且不能被修改

声明风格及最佳实践

ECMAScript 6 引入 let 和 const,从客观上为这门语言更精确地声明作用域和语义提供了更好的支持。行为怪异的 var 所造成的问题,已让 JS 社区苦恼多年。随着这两个关键字的出现,有助于提升代码质量的最佳实践方式也逐渐显现。

var 已被时代淘汰,不建议再使用。限制自己只使用 let 和 const 有助于提升代码质量,因为变量有了明确的作用域、声明位置以及不变的值。

优先使用 const,let 次之。使用 const 声明可以让浏览器运行时强制保持变量不变,也可以让静态代码分析工具提前发现不合法的赋值操作。仅在提前知道未来会有修改时,才使用 let。这样可以让开发者更有信心地推断某些变量的值永远不会变,同时也能迅速发现因意外赋值导致的非预期行为。

到此这篇关于 js 中 var、let、const 区别的文章就介绍到这了,更多相关 var、let、const 区别内容请搜索本站以前的文章或继续浏览下面的相关文章,希望大家以后多多支持本站!

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章