![React工程师修炼指南](https://wfqqreader-1252317822.image.myqcloud.com/cover/475/37323475/b_37323475.jpg)
1.1 let及const
Let及const命令是ES6新增的两种新的声明格式,用于补全ES5标准中var声明变量的不足,下面具体介绍这两种命令。
1.1.1 let命令
在JS中是通过关键字“var”来声明变量的,但是在JS中用“var”来声明变量会出现变量提升的情况,代码如下:
![](https://epubservercos.yuewen.com/D960D7/19773741008833706/epubprivate/OEBPS/Images/16_01.jpg?sign=1739155698-H5SNFIHKi747YBnBtKsJlOSD12WCxQQv-0-14a9c59c0426df8a8f069c069a02e094)
这段代码中,如果没有声明var a=10的话,打印变量a会出现“a is not defined”的错误,但是用“var”声明变量“a”后,“a”的打印结果是undefined,出现这种结果的原因是因为“var”声明变量时的提升机制(Hoisting)导致的。实际上,在执行过程中JS会把上面代码解析成如下格式:
![](https://epubservercos.yuewen.com/D960D7/19773741008833706/epubprivate/OEBPS/Images/16_02.jpg?sign=1739155698-jIsXmXg4FYn1QhzBnyZJQb9ttacoVuX4-0-da17e538431166f2a9a327ede39cbfaa)
也就是说通过“var”声明的变量系统都会把声明隐式地升至顶部,这样的特性往往会让刚接触JavaScript及习惯其他语言的开发人员不适应,导致程序出现问题。所以针对以上情况,ES6引入了let命令来声明变量。let声明和var声明用法一致,但是不会出现变量突然提升的情况,具体代码如下:
![](https://epubservercos.yuewen.com/D960D7/19773741008833706/epubprivate/OEBPS/Images/16_03.jpg?sign=1739155698-QkANG5Zea0pacrzzBsnLrGA1moMSLyEQ-0-0fe321096907d2e4a4de8c03e7692812)
利用let声明还可以把变量的作用域限制在代码块中,ES5中定义作用域有两种,全局作用域和函数作用域。ES5中没有块级作用域的概念,因此ES6中新增了块级作用域,用{}表示。块级作用域用于声明作用域之外无法访问的变量。主要有两种:
1)函数内部块级作用域:
![](https://epubservercos.yuewen.com/D960D7/19773741008833706/epubprivate/OEBPS/Images/16_04.jpg?sign=1739155698-yPM4sZf8Nq8wUiGBkdejLCdMkwH6V0Fs-0-da00d2826465c4349c9ca269c8585c9c)
2)在字符{}之间的区域:
![](https://epubservercos.yuewen.com/D960D7/19773741008833706/epubprivate/OEBPS/Images/17_01.jpg?sign=1739155698-62UeFCRMfbKtC728z2FpOTdvCmJua2Yn-0-ab0bc2d92c9c29ca867ec6ae2518eb59)
let在使用过程中除了上述情况外,还需要注意let声明过程中是禁止重复声明的:
![](https://epubservercos.yuewen.com/D960D7/19773741008833706/epubprivate/OEBPS/Images/17_02.jpg?sign=1739155698-3TLfVjpXgp7NxN61HnvLqd0NkJNlduXx-0-edeb35d48a71e8de19fd6e3a3d74afd6)
1.1.2 const命令
ES6中还提供了const关键字。使用const声明的是常量,常量的值不能通过重新赋值来改变,并且不能重新声明,所以每次通过const来声明的常量必须进行初始化。
![](https://epubservercos.yuewen.com/D960D7/19773741008833706/epubprivate/OEBPS/Images/17_03.jpg?sign=1739155698-yZIOOoT1iPusNeeHdM73cbgmJgpQCQqJ-0-eb104d43e42e7b1a89f35be5351323d6)
与其他语言不同,const在使用过程中如果声明的是对象,需要注意修改对象的属性值,但是不允许修改已经声明的对象。例如:
![](https://epubservercos.yuewen.com/D960D7/19773741008833706/epubprivate/OEBPS/Images/17_04.jpg?sign=1739155698-0xnXzsvQlXwGdC1QsAdttRbfDs56jSp0-0-309f5cd7191bc07cb042e5a804d1fcf2)
如果想让对象属性不能修改,可以借助Object.freeze函数来冻结对象,实现代码如下:
![](https://epubservercos.yuewen.com/D960D7/19773741008833706/epubprivate/OEBPS/Images/17_05.jpg?sign=1739155698-ddZDAT9YroiUzsPBW9OE5r2x9sGUPh7n-0-021a491271234cf78b490c9638c24067)
但是通过Object.freeze冻结对象需要注意不能冻结多层对象:
![](https://epubservercos.yuewen.com/D960D7/19773741008833706/epubprivate/OEBPS/Images/18_01.jpg?sign=1739155698-O4jhAsTGVaZG5lWNnSdOeMi4DO2ID9Xe-0-427d5d9a6ad9c87cbcdfce32210e5162)
要解决多层对象的冻结问题可以通过封装一个deepFreeze函数来实现:
![](https://epubservercos.yuewen.com/D960D7/19773741008833706/epubprivate/OEBPS/Images/18_02.jpg?sign=1739155698-mi80fhkTJdsv3os0cF7wS0EcbYSlYEQv-0-fc493946619c106c3a34ebfc677eabe6)
1.1.3 临时死区
let与const都是块级标识符,所以let与const都是在当前代码块内有效,常量不存在变量提升的情况。但是通过let及const声明的常量,会放在临时死区(temporal dead zone),通过下面代码可以看出:
![](https://epubservercos.yuewen.com/D960D7/19773741008833706/epubprivate/OEBPS/Images/19_01.jpg?sign=1739155698-ZGXnvx3WF9MjWjALzLHhdsbm6UWKTEzr-0-e7275cdcbf37b1a6703b36dbd5916f46)
即使通过安全的typeof操作符也会报错,原因是JavaScript引擎在扫描代码变量时,要么会把变量提升至顶部,要么会把变量放在临时死区。这里通过let来声明“a”变量,会把“a”变量放在临时死区,所以在声明之前打印就会报错。
1.1.4 循环中的let及const
在ES5标准中,for循环都是通过var来声明的,由于var没有独立的作用域,导致在循环中创建函数时会出现结果和思路不一致的情况。代码如下:
![](https://epubservercos.yuewen.com/D960D7/19773741008833706/epubprivate/OEBPS/Images/19_02.jpg?sign=1739155698-BRHPfyr8R2XlE7SNbOLNH2QfiMSIHBXR-0-06135d45dc9087f3a8df801a12dd846d)
循环执行结果并不是预想的0,1,2,3,4而是5个5,这是因为var声明在循环中作用域共用,并且会把i保存在全局作用域中。要解决循环中保存函数的问题,可以利用闭包创建独立作用域。将代码改写如下:
![](https://epubservercos.yuewen.com/D960D7/19773741008833706/epubprivate/OEBPS/Images/19_03.jpg?sign=1739155698-gi3l9yzRmrw8dXfaYFpiMO7F70f0gspl-0-a68bc1d9ec59bdf2a21c3d2536247c52)
这样通过自执行函数就可以解决循环中创建函数的问题。但是利用ES6中let及const提供的块级作用域可以让上面写法变得更加简单。代码如下:
![](https://epubservercos.yuewen.com/D960D7/19773741008833706/epubprivate/OEBPS/Images/20_01.jpg?sign=1739155698-rUJpuqLdiHbyid1fKgp4Neg70sGynDLg-0-4f40056e4cf0fa910886f958ecd52b10)
这样得到的结果就是预想的结果。由于const不能被重新赋值,所以在for循环中如果利用const来定义变量会报错。代码如下:
![](https://epubservercos.yuewen.com/D960D7/19773741008833706/epubprivate/OEBPS/Images/20_02.jpg?sign=1739155698-68sLfu7ioWWIfWrQ2XqmE5H0ScK7SeeL-0-554f961a16783a86c205e122ae36508b)
在for-in或for-of循环中使用const时,方法与let一致,代码如下:
![](https://epubservercos.yuewen.com/D960D7/19773741008833706/epubprivate/OEBPS/Images/20_03.jpg?sign=1739155698-UK5ntEcZteD5IE6dlUvq6kD2Gf86iRoj-0-8de8195a7677b5086b6f8df91e6ffb8b)