1. 作用域
- var:具有函数作用域。在函数内部声明的
var
变量,在整个函数内都可访问,即使在声明之前使用,会出现变量提升现象(但值为undefined
)。例如:
function test() {
console.log(a); // undefined
var a = 1;
}
test();
- let:具有块级作用域。块级作用域是由
{}
包裹的一段代码区域。在块级作用域内声明的let
变量,仅在该块级作用域内有效。例如:
{
let b = 2;
console.log(b); // 2
}
console.log(b); // ReferenceError: b is not defined
- const:同样具有块级作用域。一旦声明,必须立即初始化,且不能重新赋值(对于对象和数组,其引用不能改变,但对象属性和数组元素可修改)。例如:
{
const c = 3;
console.log(c); // 3
}
console.log(c); // ReferenceError: c is not defined
2. 提升
- var:存在变量提升,会将声明提升到函数或全局作用域的顶部,但初始化留在原地。所以可以先使用后声明。
- let和const:不存在变量提升,在声明之前使用会导致
ReferenceError
,这一区域被称为“暂时性死区”(TDZ)。例如:
console.log(d); // ReferenceError: Cannot access 'd' before initialization
let d = 4;
3. 重新赋值
var e = 5;
var e = 6;
console.log(e); // 6
e = 7;
console.log(e); // 7
let f = 8;
f = 9;
console.log(f); // 9
let f = 10; // SyntaxError: Identifier 'f' has already been declared
- const:不能重新赋值(基本类型),对于复合类型(对象、数组),虽然不能改变引用,但内部属性或元素可修改。例如:
const obj = { key: 'value' };
obj.key = 'new value';
console.log(obj); // { key: 'new value' }
const arr = [1, 2];
arr.push(3);
console.log(arr); // [1, 2, 3]
obj = { newKey: 'newValue' }; // TypeError: Assignment to constant variable.
arr = [4, 5]; // TypeError: Assignment to constant variable.
实际应用场景中的优劣
- var:
- 优点:在旧版本JavaScript中广泛使用,兼容性好。适用于需要在函数内共享变量的场景,虽然可能会导致意外覆盖,但在一些简单的函数逻辑中使用方便。
- 缺点:容易导致变量泄漏,由于函数作用域和变量提升,可能会出现难以调试的问题,尤其是在大型项目中。
- let:
- 优点:块级作用域使得变量的作用范围更加清晰,避免了在块内意外修改外部变量的问题。适用于循环中声明迭代变量等场景,保证每次迭代的变量相互独立。例如:
for (let i = 0; i < 5; i++) {
setTimeout(() => {
console.log(i); // 依次输出0, 1, 2, 3, 4
}, 1000);
}
- **缺点**:相比`var`,需要更多注意块级作用域的界定,对于不熟悉块级作用域概念的开发者可能会有理解成本。
- const:
- 优点:适用于声明常量,保证数据的不可变性,提高代码的稳定性和可维护性。对于对象和数组的使用,有助于防止意外修改引用,提高代码的可预测性。
- 缺点:声明时必须初始化,对于一些需要动态赋值的场景不太适用。同时,对于对象和数组内部的修改不易察觉,可能导致数据的意外变更。