ES6 中的 let 和 const 变量声明
ES6(ECMAScript 6),也称为 ECMAScript 2015,是 JavaScript 的第六个版本,带来了许多新特性和语法改进。这些新特性使得 JavaScript 更加现代化和强大,提升了代码的可读性和可维护性。而ES6引入了新的变量声明方式 let 和 const,这两种方式相较于传统的 var 声明提供了更为严格和清晰的作用域管理。以下是对 let 和 const 的主要特性和使用场景的总结。
let 与const命令
let 的本质
let 是 ES6 引入的一种变量声明方式,主要用于解决 var 声明变量时的一些问题。let 的本质特性包括:
1. 块级作用域
let声明的变量只在其所在的代码块内有效,这与var不同。var声明的变量是函数作用域或全局作用域。
{
let x = 10;
var y = 20;
}
console.log(x); // 报错:ReferenceError: x is not defined
console.log(y); // 输出: 20
2. 不允许重复声明
- 在同一作用域内,使用
let声明同一个变量会导致错误,而var允许重复声明。
let a = 1;
// let a = 2; // 报错:Identifier 'a' has already been declared
var b = 1;
var b = 2; // 合法,b 的值会被更新为 2
3. 提升(Hoisting)
let声明的变量会被提升到所在作用域的顶部,但在声明之前是不可用的。这种现象称为“暂时性死区”(Temporal Dead Zone, TDZ)。
console.log(c); // 报错:ReferenceError: Cannot access 'c' before initialization
let c = 3;
4. 适用于循环中的作用域
- 在循环中使用
let声明的变量,每次迭代都会创建一个新的作用域,这在处理异步操作时非常有用。
for (let i = 0; i < 3; i++) {
setTimeout(() => {
console.log(i); // 输出: 0, 1, 2
}, 1000);
}
使用 var 声明的变量会导致所有的回调函数共享同一个 i,输出结果为 3 三次。
const 的本质
const 是 ES6 引入的一个关键字,用于声明常量。它的本质特性主要体现在以下几个方面:
1. 固定的引用
const声明的变量指向的内存地址是固定的,这意味着你不能重新赋值给该变量。换句话说,const确保变量的引用不变,但并不意味着引用的数据本身不可变。
const a = 10;
// a = 20; // 报错:Assignment to constant variable.
2. 复合类型的可变性
- 对于复合类型(如对象和数组),
const变量指向的是一个内存地址,而这个地址保存的是一个指向实际数据的引用。因此,虽然const保证了这个引用(指针)不会改变,但它指向的数据结构本身是可以修改的。
const obj = { name: 'Alice' };
obj.name = 'Bob'; // 这是合法的,obj 的内容被修改
console.log(obj); // 输出: { name: 'Bob' }
// obj = { name: 'Charlie' }; // 报错:Assignment to constant variable.
3. 块级作用域
const也具有块级作用域,与let类似。它只在声明它的代码块内有效。
{
const x = 5;
}
console.log(x); // 报错:ReferenceError: x is not defined
4. 不允许重复声明
- 在同一作用域内,使用
const声明同一个变量会导致错误。
const b = 1;
// const b = 2; // 报错:Identifier 'b' has already been declared
5. 提升(Hoisting)
const声明的变量会被提升到作用域的顶部,但在声明之前是不可用的,这种现象称为“暂时性死区”(Temporal Dead Zone, TDZ)。
console.log(c); // 报错:ReferenceError: Cannot access 'c' before initialization
const c = 3;
简单示例:
let b = 0;
const c = 2;
for (let b = 1; b < 5; b++) {
var a = 0;
const c = 1;
}
// c = 4; // 这一行会报错,因为 const 变量不能重新赋值
b = 3;
console.log(b); // 输出: 3
console.log(a); // 输出: 0
console.log(c); // 输出: 2
if (1) {
let b = 1;
}
console.log(b); // 输出: 3
let d = 2;
if (1) {
console.log(d); // 输出: 2
let c = 1;
}
解释
-
let b = 1的作用域:- 在
for循环内部,let b = 1声明的变量b只在循环内部有效,循环结束后,外部的b仍然是0。因此,console.log(b)输出的是3,这是因为在循环外部将b赋值为3。
- 在
-
var a = 0的作用域:var a = 0声明的变量a是在函数或全局作用域中有效的,因此在循环外部可以访问到。即使在循环内部重新声明a,外部仍然可以访问到原来的a,所以console.log(a)输出0。
-
const c = 1的作用域:const c = 1声明的变量c只在循环内部有效,外部的const c = 2不受影响。因此,console.log(c)输出的是2,而不是1。
-
if语句中的let:- 在
if语句块中,let b = 1声明的b只在if语句内部有效,外部的b不受影响。因此,console.log(b)输出的是3。
- 在
-
let d = 2的作用域:- 在
if语句中,console.log(d)可以访问到外部的d,所以输出2。而let c = 1只在if语句内部有效,不会影响外部的c。
- 在
小结
let 和 const 的引入使得 JavaScript 的变量管理更加严谨,避免了 var 的一些常见问题,提升了代码的可读性和可维护性。建议在编写现代 JavaScript 时优先使用 let 和 const,以确保更好的代码质量。