![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=1738887467-PofgMIzsrA6fw27q91Pxx7xXjds4KjQi-0-6e555382db8fbbd46ed0d2e7024e8807)
这段代码中,如果没有声明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=1738887467-ZyS1CT4PF46qwGQ2ZRDHVoTCTVza0Mut-0-4906464fdb3a551b1c5d6dc473eec73b)
也就是说通过“var”声明的变量系统都会把声明隐式地升至顶部,这样的特性往往会让刚接触JavaScript及习惯其他语言的开发人员不适应,导致程序出现问题。所以针对以上情况,ES6引入了let命令来声明变量。let声明和var声明用法一致,但是不会出现变量突然提升的情况,具体代码如下:
![](https://epubservercos.yuewen.com/D960D7/19773741008833706/epubprivate/OEBPS/Images/16_03.jpg?sign=1738887467-3w1YfLW1B71Z23v4gwQ35WcatgAMaiMv-0-88c1d5dae1dc543b75b30e81c7614d88)
利用let声明还可以把变量的作用域限制在代码块中,ES5中定义作用域有两种,全局作用域和函数作用域。ES5中没有块级作用域的概念,因此ES6中新增了块级作用域,用{}表示。块级作用域用于声明作用域之外无法访问的变量。主要有两种:
1)函数内部块级作用域:
![](https://epubservercos.yuewen.com/D960D7/19773741008833706/epubprivate/OEBPS/Images/16_04.jpg?sign=1738887467-nMXpZ9Ic3SY64wZD8tIi4I7TcMSSGcsa-0-e1f682beafefa2425a4761ec73e7ae7d)
2)在字符{}之间的区域:
![](https://epubservercos.yuewen.com/D960D7/19773741008833706/epubprivate/OEBPS/Images/17_01.jpg?sign=1738887467-AsmoNW3bugS4os0C8u047DYLjj3kNOf7-0-0111744d5679b03a28c536e978845c6b)
let在使用过程中除了上述情况外,还需要注意let声明过程中是禁止重复声明的:
![](https://epubservercos.yuewen.com/D960D7/19773741008833706/epubprivate/OEBPS/Images/17_02.jpg?sign=1738887467-VICiwQxAZy6Ys8LxDic6MXntWlVfwTnL-0-b078268c746a169d3020356a52819151)
1.1.2 const命令
ES6中还提供了const关键字。使用const声明的是常量,常量的值不能通过重新赋值来改变,并且不能重新声明,所以每次通过const来声明的常量必须进行初始化。
![](https://epubservercos.yuewen.com/D960D7/19773741008833706/epubprivate/OEBPS/Images/17_03.jpg?sign=1738887467-1pXmsNdwbputZFMOTSnpPO94RrUHFiTc-0-c655d00dc1599c0dd6201a78ecbe691c)
与其他语言不同,const在使用过程中如果声明的是对象,需要注意修改对象的属性值,但是不允许修改已经声明的对象。例如:
![](https://epubservercos.yuewen.com/D960D7/19773741008833706/epubprivate/OEBPS/Images/17_04.jpg?sign=1738887467-YY17Sy0zaHrdQfuobxzrlEyctdARPnsf-0-9c41eec5b0f7cf354307a0cd9f60aab6)
如果想让对象属性不能修改,可以借助Object.freeze函数来冻结对象,实现代码如下:
![](https://epubservercos.yuewen.com/D960D7/19773741008833706/epubprivate/OEBPS/Images/17_05.jpg?sign=1738887467-rvZ5bfMYxWrTmEVqnEdWSdemh2gBXqzy-0-c45b69ef7053156d867e1b7d75deb524)
但是通过Object.freeze冻结对象需要注意不能冻结多层对象:
![](https://epubservercos.yuewen.com/D960D7/19773741008833706/epubprivate/OEBPS/Images/18_01.jpg?sign=1738887467-PqdZjaOCUEPaoKfs8jHFvkrbfAOQeAvM-0-88946b7422ac393ced00e02b19bd7ae3)
要解决多层对象的冻结问题可以通过封装一个deepFreeze函数来实现:
![](https://epubservercos.yuewen.com/D960D7/19773741008833706/epubprivate/OEBPS/Images/18_02.jpg?sign=1738887467-L8Q5cpu5zhOhJ6HKDQPQrhQ6QgLjiTBe-0-1fd377050eff5fe9eccac3b13dd48a5a)
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=1738887467-rQ1Yk6G5HyZC4nUr1XzRexe4mly2bUyW-0-59ea42d289a60903d1164ac35b486a8a)
即使通过安全的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=1738887467-Pkjuov79bpvNJ4Cz4I5u7KtzgtNA9T9P-0-281099284dba993981bc57a1c3413d95)
循环执行结果并不是预想的0,1,2,3,4而是5个5,这是因为var声明在循环中作用域共用,并且会把i保存在全局作用域中。要解决循环中保存函数的问题,可以利用闭包创建独立作用域。将代码改写如下:
![](https://epubservercos.yuewen.com/D960D7/19773741008833706/epubprivate/OEBPS/Images/19_03.jpg?sign=1738887467-kXZv0PVxV9UZVNq7gNAX6Iho1b2rOTUn-0-39b547c3bd2b06849a660637666cd1b7)
这样通过自执行函数就可以解决循环中创建函数的问题。但是利用ES6中let及const提供的块级作用域可以让上面写法变得更加简单。代码如下:
![](https://epubservercos.yuewen.com/D960D7/19773741008833706/epubprivate/OEBPS/Images/20_01.jpg?sign=1738887467-m9W1Ksb8BmlkszXhi9arnFI2mCxx2iwE-0-14d8172d48ad793f7c8435ccad89622c)
这样得到的结果就是预想的结果。由于const不能被重新赋值,所以在for循环中如果利用const来定义变量会报错。代码如下:
![](https://epubservercos.yuewen.com/D960D7/19773741008833706/epubprivate/OEBPS/Images/20_02.jpg?sign=1738887467-jje5AW3vFDlo5xPE6C6cXMgjllTmT5cD-0-fbfb1b3089f75d1a6b9b2fd78e9dee52)
在for-in或for-of循环中使用const时,方法与let一致,代码如下:
![](https://epubservercos.yuewen.com/D960D7/19773741008833706/epubprivate/OEBPS/Images/20_03.jpg?sign=1738887467-fW6q3z68F2pxJUGRppG75htyCl6RwRvs-0-a102d0776ee61f4490bec013bb834229)