JavaScript let 和 const

在 JavaScript 的发展过程中,声明变量的方式也在不断演进。在 ES6 之前,我们主要使用 var 关键字来声明变量。然而,var 存在非常多的问题,比如变量提升、作用域限制等。如果在复杂项目中使用 var,很容易会导致各种问题。

为了解决 var 本身的缺陷,ES6 引入了 let 和 const 关键字,它们为我们提供了更清晰、更可控的变量声明方式。

使用 var 声明变量 (了解)

在 ES6 之前,我们都是使用 var 来声明变量。了解 var 的一些特点,有助于我们理解 let 和 const 的优势。

语法:

var 变量名 = 值;

说明:

使用 var 声明的变量,其作用域是 “函数作用域” 或 “全局作用域” ,但没有 “块级作用域” 。也就是说,像在 “if 语句” 或 “for 循环” 中用 var 声明的变量,在外部也是可以访问到的。

其中,使用 var 声明的变量存在 “变量提升(Hoisting)” 的现象,即变量的声明会被提升到其作用域的顶部,但赋值不会提升。

示例 1:var 的作用域

if (true) {
    var title = "绿叶网";
    console.log(title);
}
console.log(title);

运行结果如下。

绿叶网
绿叶网

分析:

在这个例子中,我们在 if 块内部使用 var 声明了一个变量,但却发现在 if 块外部仍然可以访问到,这就是 var 没有块级作用域的表现。

示例 2:var 的变量提升

console.log(title);
var title = "绿叶网";
console.log(title);

运行结果如下。

undefined
绿叶网

分析:

对于使用 var 声明的变量,会被提升到作用域的顶部,因此上面代码等价于:

var title;
console.log(title);
title = "绿叶网";
console.log(title);

虽然 var title = "绿叶网"; 这句代码放到 第一个 console.log(title); 之后,但由于 var title 的声明被提升到了作用域顶部,所以第一个 console.log(title) 不会报错,只是输出 undefined(变量已声明但未赋值)。

使用 let 声明变量

在 ES6 之后,我们可以使用 let 来声明一个变量。let 解决了 var 上面提到的这些问题,提供了更好的变量管理。

语法:

let 变量名 = 值;

说明:

let 声明的变量具有块级作用域。这意味着变量只在声明它的块(例如 if 语句、for 循环、函数体内部)内部有效。

此外,let 不存在变量提升。在使用 let 声明变量之前访问它会报错(暂时性死区)。并且在同一个作用域内,不允许使用 let 重复声明同一个变量名。

提示: 在全局作用域中,使用 var 声明的变量会自动成为 window 对象的属性(如 window.title),而 let 和 const 声明的变量则不会。这避免了全局变量污染 window 对象。

示例 3:let 的块级作用域

if (true) {
    let title = "绿叶网";
    console.log(title);
}
console.log(title);

运行结果如下。

绿叶网
(报错)ReferenceError: title is not defined

分析:

由于 let 声明的变量具有块级作用域,因此在 if 块外部访问 if 内部使用 let 声明的变量,会直接报错。

示例 4:let 不存在变量提升 ( 暂时性死区 )

console.log(title);
let title = "绿叶网";
console.log(title);

运行结果如下。

(报错)ReferenceError: Cannot access 'title' before initialization

分析:

在 let title = "绿叶网"; 这行代码执行之前,title 尚处于 “暂时性死区”,此时访问它会直接报错。

示例 5:let 不允许重复声明

let title = "绿叶网";
let title = "JavaScript";
console.log(title);

运行结果如下。

(报错)SyntaxError: Identifier 'title' has already been declared

分析:

在同一个作用域内,如果使用 let 声明同一个变量名,会直接导致报错。

使用 const 声明常量

在 ES6 之后,我们可以使用 const 来声明一个常量。const 常量一旦声明并赋值后,其值就不能再被重新赋值。

语法:

const 常量名 = 值;

说明:

对于 const 来说,小伙伴们需要清楚以下几点。

  • 与 let 一样,const 声明的常量也具有块级作用域。
  • 与 let 一样,const 声明的常量也不存在变量提升,且不允许在同一个作用域内重复声明。
  • const 声明的常量在声明时必须进行初始化(赋值),否则会报错。

示例 6:const 常量不允许被重新赋值

const PI = 3.14;
PI = 3.1415;
console.log(PI);

运行结果如下。

(报错)TypeError: Assignment to constant variable.

分析:

对于使用 const 声明的常量,如果尝试对其赋新值,则会直接报错。

示例 7:常量对象不可被重新赋值

const user = {
    name: "阿莫",
    age: 18
};

user.age = 20;    // 允许修改对象的属性
console.log(user);

运行结果如下。

{ name: '阿莫', age: 20 }

分析:

在这个例子中,user 是一个对象。如果我们尝试为 user 重新赋值,此时程序会直接报错,比如:

const user = {
    name: "阿莫",
    age: 20
};
user = { name: "阿莫", age: 20};    // 此处进行了重新赋值,则会报错
console.log(user);

user 被声明为常量,它始终指向同一个对象。虽然不能将 user 重新赋值给一个新的对象,但可以修改 user 对象内部的属性,比如使用 user.age 将 age 从 18 改为 20。

示例 8:常量数组的内部元素可变

const colors = ["红", "绿", "蓝"];

colors[0] = "red";    // 允许修改数组的元素
console.log(colors);

运行结果如下。

[ 'red', '绿', '蓝' ]

分析:

在这个例子中,colors 被声明为常量数组,它始终指向同一个数组。虽然不能将 colors 重新赋值给一个新的数组,但我们可以修改 colors 数组内部的元素,比如将第一个元素从 "红" 改为 "red"。

最佳实践

在实际项目开发中,我们应该遵循 “优先使用 const、次之使用let” 的原则,这也是编写高质量 JavaScript 代码的一个最佳实践。至于为什么,我们在之前 “JavaScript 常量” 一节的末尾已经详细说过了。

给站长反馈

绿叶网正在不断完善中,小伙伴们如果发现任何问题,还望多多给站长反馈,谢谢!

邮箱:lvyenet@vip.qq.com

「绿叶网」服务号
绿叶网服务号放大
关注服务号,微信也能看教程。
绿叶网服务号