前言
JavaScript 中 var
、let
和 const
都是用来声明变量的,但它们在作用域规则、变量提升(Hoisting)、以及可否重新赋值等方面存在显著区别。
变量作用域
-
var
:具有函数作用域。在函数内部声明的var
变量在整个函数体中都是可见的,但在其外部则不可见。同时,在一个函数内部,即使变量声明语句出现在条件或循环等块级结构之后,该变量在整个函数范围内仍可访问,即存在变量提升现象。 -
let
和const
:具有块级作用域。在任意代码块(如{}
内部)中声明的let
或const
变量仅在当前代码块内有效,离开该块后就无法访问。它们不存在变量提升,必须先声明再使用,否则会报错。
变量声明和初始化
var
:可以不初始化就声明,如果不初始化,其值为undefined
。let
:也可以不初始化就声明,但与var
不同的是,它遵循“暂时性死区”规则,即在声明前引用该变量会抛出错误。const
:必须初始化,因为它定义的是常量,一旦声明并赋值后就不能改变其值。但是要注意,对于对象和数组类型的const
声明,虽然不能直接修改变量指向,但可以修改其内容(例如更改对象属性或数组元素)。
重复声明
var
:在同一作用域内可以多次声明同一个变量,后面的声明不会报错,会覆盖前面的声明。let
和const
:在同一作用域内不允许重复声明同一变量,如果试图再次声明,则会抛出语法错误。
值可变性
var
和let
:声明的变量值可以被重新赋值。const
:声明的常量在其生命周期内是不可变的,不能重新赋值给新的数据。
代码示例
// var 示例:
function testVar() {
console.log(a); // 输出:undefined,虽然变量声明在后,但因变量提升仍可访问
var a = 5;
if (true) {
var a = 10; // 同名变量覆盖,整个函数内a的值为10
console.log(a); // 输出:10
}
console.log(a); // 输出:10
}
testVar();
// let 示例:
if (true) {
let b = 5;
console.log(b); // 输出:5
}
console.log(b); // 报错:b is not defined,因为b的作用域仅限于if块内部
for (let i = 0; i < 3; i++) {
console.log(i); // 输出:0, 1, 2
}
console.log(i); // 报错:i is not defined,因为i的作用域仅限于for循环内部
// const 示例:
const c = 10;
console.log(c); // 输出:10
c = 20; // 报错:Assignment to constant variable., 因为试图修改常量c的值是不允许的
const d = { value: 1 };
console.log(d); // 输出:{value: 1}
d.value = 2; // 此操作合法,因为修改的是对象内容而非改变d本身指向
console.log(d); // 输出:{value: 2}
// 尝试重复声明:
var e = 1;
var e = 2; // 合法,后面的声明覆盖前面的声明
let f = 1;
let f = 2; // 报错:Identifier 'f' has already been declared
const g = 1;
const g = 2; // 报错:Identifier 'g' has already been declared
总结
- 使用
var
时要小心变量提升带来的副作用,特别是在涉及复杂作用域逻辑时。 let
用于需要块级作用域且可能需要重新赋值的场景。const
应用于那些不应该被重新赋值的变量,用来强制保持不变性,提高代码可读性和减少意外修改的风险。