前言
作为前端经典八股文之一,ES6新特性之 let、const 可谓各大面试常客之一,在 ECMAScript 6之前,声明变量使用 var 关键字,ECMAScript 6 新增了 const 和 let 关键字用以弥补var关键字的缺陷。
一、var 的缺点
1. var 允许重复声明变量
使用var语句重复声明同一个变量不仅是合法的,也不会造成任何错误,会导致数据被覆盖,这在其他语言中是十分少见的。
var a = "VeryCool";
var a = "稀土掘金";
console.log(a); // 输出稀土掘金
2. var 会污染全部变量
var 定义的局部变量会自动添加全局对象 window,造成全局对象被污染,变得难以维护。
var VeryCool = '稀土掘金';
console.log(window);
此时打印window可以发现声明的变量已被挂载到全局对象。
3. var 存在变量提升
无论我们在全局作用域还是在局部作用域中,使用var关键字声明的变量,都会被提升到该作用域的最顶部,这就是所谓的"变量提升"。
console.log(VeryCool); // 输出undefined,说明变量已被声明,还未赋值
var VeryCool = "稀土掘金";
😕原因: JavaScript引擎解析分为变量声明和变量赋值两个阶段,首先会将所有被声明的变量提升到作用域顶部,再按顺序执行代码。上述代码执行过程如下:
var VeryCool; // 1.先声明变量
console.log(VeryCool); // 2.打印变量
VeryCool = "稀土掘金"; // 3.再为变量赋值
⚠注意: 函数声明也会提升,并且优先级高于变量提升(先声明函数,再声明变量)
fun();
console.log(VeryCool);
var VeryCool = "稀土掘金";
function fun() {
console.log("点个赞吧!");
}
上述代码会先输出点个赞吧!再输出undefined,其执行过程如下:
function fun() { // 1.先声明函数
console.log("点个赞吧!");
}
var VeryCool; // 2.再声明变量
fun(); // 3.先调用函数
VeryCool = "稀土掘金"; // 4.再为变量赋值
💣变量提升缺点:
1.无用的变量不能被及时销毁(如for循环结束后,变量 i 依然存在)
2.同名变量可能被无意间覆盖
二、let 和 const 优点
1. 暂时性死区(Temporal Dead Zone)
😊理解: let和const声明的变量从一开始就形成了封闭作用域,在代码未执行到变量初始化(首次赋值)之前,对变量进行访问或者赋值就会报错。所以使用let或const变量初始化之前,都是不可用的,称之为暂时性死区。
console.log(VeryCool); // 输出:ReferenceError:初始化之前无法访问“VeryCool”
let VeryCool = "稀土掘金";
2. 块级作用域
😊理解: let和const声明的变量是块级作用域,即仅在当前 { } 中有效,无法从块的外部访问块内部的变量。而var在函数内部声明的变量是函数作用域,在函数内部都可以访问到。(var在全局声明的变量,是全局作用域)
function fun() {
{
var Very = "稀土";
let Cool = "掘金"
}
console.log(Very); // 输出稀土
console.log(Cool); // 输出Cool is not defined
}
fun()
😃优点:
1.避免变量冲突,块内声明的变量仅在块内有效,将私有变量和全局对象分离(块外无法访问块内变量,块内变量也会覆盖块外同名变量),防止同名变量冲突。
2.利于内存回收,防止私有变量泄露为全局变量。(如for循环的 i )
3. 禁止重复声明
😊理解: 在同一作用域内,无法重复声明同一个变量。
let VeryCool = "稀土";
let VeryCool = "掘金";
console.log(VeryCool); // 输出:已声明标识符"VeryCool"
4. 不会全局挂载
😊理解: var在全局作用域中声明的变量会挂载到window上称为window对象的属性,而let不会。
var Very = "稀土";
let Cool = "掘金";
console.log(window); // 仅Very被挂载
三、const 和 let 区别
😊理解: const 声明的变量也是块级作用域,不存在变量提升,拥有暂时性死区,与 let 基本相同。
🆚不同的是:
1.
const声明的是一个只读常量,不能修改。
const VeryCool = "稀土";
VeryCool = "掘金";
console.log(VeryCool); // 输出:禁止给常量变量赋值
2.
const声明的常量在声明时就必须要赋值,不能只声明不赋值。
const VeryCool;
console.log(VeryCool); // 输出:常量声明中缺少初始值设定
四、const常量也可以被修改
🤔在实际开发中,经常可以发现,用const定义的对象或数组可以被修改,如下:
const VeryCool = {
name: "稀土掘金",
age: 18,
};
VeryCool.age = 20;
console.log(VeryCool); // 输出age为20
💡原因: const声明只限制了他所声明的变量指向的内存地址不变。
const定义的常量是
基本数据类型(数值、字符串、布尔值),由于数据保存在栈中,所以无法修改变量。
const定义的常量是
引用数据类型,仅在栈中保存指向堆内存的指针,const只能限制这个指针所指向的堆内存地址不变,而无法限制堆中的数据是否改变,所以修改引用数据类型内部的属性,不会受到const限制。
总结
- var允许变量提升,函数作用域,可以重复声明。
- let不允许变量提升,块级作用域,不能重复声明,不会全局挂载。
- const不允许变量提升,块级作用域,不能重复声明,不会全局挂载,声明基本数据类型禁止修改,声明引用数据类型可以修改。