ES6 (ECMAScript 2015) 引入了两个重要的新关键字:let
和 const
,它们彻底改变了 JavaScript 的作用域规则,为开发者提供了更精确的变量声明方式。本文将深入探讨块级作用域的概念以及如何正确使用 let
和 const
。
理解块级作用域
在 ES6 之前,JavaScript 只有函数作用域和全局作用域,使用 var
声明的变量要么是函数级的,要么是全局的。ES6 引入了块级作用域,即由一对花括号 {}
界定的代码块(如 if
语句、for
循环等)形成的作用域。
javascript
{
// 这是一个块级作用域
let x = 10;
console.log(x); // 10
}
console.log(x); // ReferenceError: x is not defined
let 关键字
let
允许你声明一个块级作用域的局部变量:
- 块级作用域:
let
声明的变量只在声明它的块或子块中可用 - 不存在变量提升:与
var
不同,let
声明的变量不会提升到作用域顶部 - 暂时性死区:在声明前访问
let
变量会导致 ReferenceError - 不允许重复声明:在同一作用域内不能重复声明同名变量
javascript
// 示例1:块级作用域
function letExample() {
if (true) {
let y = 20;
console.log(y); // 20
}
console.log(y); // ReferenceError: y is not defined
}
// 示例2:for循环中的let
for (let i = 0; i < 5; i++) {
setTimeout(() => console.log(i), 100); // 输出0,1,2,3,4
}
const 关键字
const
用于声明块级作用域的常量:
- 必须初始化:声明时必须赋值
- 不可重新赋值:一旦赋值,不能改变(对于基本类型)
- 不是完全不可变:对于对象和数组,内容可以修改,只是不能重新赋值
- 其他特性:与
let
相同的块级作用域、暂时性死区等特性
javascript
// 基本类型
const PI = 3.14159;
PI = 3; // TypeError: Assignment to constant variable
// 对象和数组
const person = { name: 'Alice' };
person.name = 'Bob'; // 允许
person = { name: 'Charlie' }; // TypeError
const numbers = [1, 2, 3];
numbers.push(4); // 允许
numbers = [5, 6]; // TypeError
使用建议
- 默认使用 const:除非你知道变量需要重新赋值,否则优先使用
const
- 需要重新赋值时用 let:当变量需要被重新赋值时使用
let
- 避免使用 var:在现代 JavaScript 开发中,基本不再需要使用
var
- 注意对象和数组的"常量性":
const
只保证变量引用的不变性,不保证引用对象的不变性
常见误区
- 认为 const 创建不可变对象:实际上只是创建不可重新赋值的变量
- 在循环中使用不当:
for...in
和for...of
中可以使用const
,但传统for
循环需要let
- 过度使用 let:很多情况下
const
已经足够
javascript
// 正确使用const的循环
const arr = [1, 2, 3];
for (const item of arr) {
console.log(item);
}
// 需要let的循环
for (let i = 0; i < arr.length; i++) {
console.log(arr[i]);
}
总结
let
和 const
的引入使 JavaScript 的作用域管理更加清晰和可靠。通过理解块级作用域的概念并遵循最佳实践,可以编写出更安全、更易维护的代码。记住:默认使用 const
,需要重新赋值时用 let
,尽量避免使用 var
。