![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=1738895789-dONvca5Ca07hUJcYpS0jkY2es262ueFQ-0-0c66fa011e414b2ae92b51b74376b22b)
这段代码中,如果没有声明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=1738895789-VdEKoBAqQaYy1qg6pvg2TwgFFQgJTqe5-0-606bedb18b8059e426ef30a93ae214eb)
也就是说通过“var”声明的变量系统都会把声明隐式地升至顶部,这样的特性往往会让刚接触JavaScript及习惯其他语言的开发人员不适应,导致程序出现问题。所以针对以上情况,ES6引入了let命令来声明变量。let声明和var声明用法一致,但是不会出现变量突然提升的情况,具体代码如下:
![](https://epubservercos.yuewen.com/D960D7/19773741008833706/epubprivate/OEBPS/Images/16_03.jpg?sign=1738895789-uRUHnOjYK4mfkChUgh28aYDNGnhfdqHf-0-51f4588ad386819c60669140890c250f)
利用let声明还可以把变量的作用域限制在代码块中,ES5中定义作用域有两种,全局作用域和函数作用域。ES5中没有块级作用域的概念,因此ES6中新增了块级作用域,用{}表示。块级作用域用于声明作用域之外无法访问的变量。主要有两种:
1)函数内部块级作用域:
![](https://epubservercos.yuewen.com/D960D7/19773741008833706/epubprivate/OEBPS/Images/16_04.jpg?sign=1738895789-BZI20ecKd1hkI1mlS0CbUf7cgqMVykSp-0-5eece3f053ad43f802f8e1edb6b6e2f5)
2)在字符{}之间的区域:
![](https://epubservercos.yuewen.com/D960D7/19773741008833706/epubprivate/OEBPS/Images/17_01.jpg?sign=1738895789-wz23EjaZBZZm8VzPV3vNMrLlyNQ0JKAh-0-d3b466191e7d13d375ad3c23f741b1f9)
let在使用过程中除了上述情况外,还需要注意let声明过程中是禁止重复声明的:
![](https://epubservercos.yuewen.com/D960D7/19773741008833706/epubprivate/OEBPS/Images/17_02.jpg?sign=1738895789-YzHjF88rMGl1XSvSdGbznsZdsRRLpqte-0-98b3ebd555089df055a2d8d9b9e7ccf5)
1.1.2 const命令
ES6中还提供了const关键字。使用const声明的是常量,常量的值不能通过重新赋值来改变,并且不能重新声明,所以每次通过const来声明的常量必须进行初始化。
![](https://epubservercos.yuewen.com/D960D7/19773741008833706/epubprivate/OEBPS/Images/17_03.jpg?sign=1738895789-vMHFJx9fuvoPxoT97JeWMXBQcnvVo5R6-0-d6a004b01da8a3672f8762b14d9f6b67)
与其他语言不同,const在使用过程中如果声明的是对象,需要注意修改对象的属性值,但是不允许修改已经声明的对象。例如:
![](https://epubservercos.yuewen.com/D960D7/19773741008833706/epubprivate/OEBPS/Images/17_04.jpg?sign=1738895789-wKPNZNt0qm9AjJL7Sj2xG33N8Eukel9n-0-edcd362d1a61926d777e75ae647a27f3)
如果想让对象属性不能修改,可以借助Object.freeze函数来冻结对象,实现代码如下:
![](https://epubservercos.yuewen.com/D960D7/19773741008833706/epubprivate/OEBPS/Images/17_05.jpg?sign=1738895789-nsymiAeFvVAQbnrIFJRwFc1bU0IViYs1-0-8fb8b8065f9722a20734efbb26ead496)
但是通过Object.freeze冻结对象需要注意不能冻结多层对象:
![](https://epubservercos.yuewen.com/D960D7/19773741008833706/epubprivate/OEBPS/Images/18_01.jpg?sign=1738895789-2X4Yft4s7X0VnFnYjIRJM0RvjSa8bwoV-0-fa364bf85d9e337b480fd9ae6546dbf3)
要解决多层对象的冻结问题可以通过封装一个deepFreeze函数来实现:
![](https://epubservercos.yuewen.com/D960D7/19773741008833706/epubprivate/OEBPS/Images/18_02.jpg?sign=1738895789-9Hdpx9dnabO6MUBBbXR8aiMbdFRXtKwS-0-6706949e351dbe9664cdaad1e060fdc2)
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=1738895789-je47M0Ks9GxqNq8UWVHfEAAjskRLnYhA-0-245ecdbc6237d5bb664dde200d3f2cd1)
即使通过安全的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=1738895789-DakFJKQL62Q2ocIcfhGHmW5ZifihArdG-0-3f87e8f0e35bcaea74a21c673ce01777)
循环执行结果并不是预想的0,1,2,3,4而是5个5,这是因为var声明在循环中作用域共用,并且会把i保存在全局作用域中。要解决循环中保存函数的问题,可以利用闭包创建独立作用域。将代码改写如下:
![](https://epubservercos.yuewen.com/D960D7/19773741008833706/epubprivate/OEBPS/Images/19_03.jpg?sign=1738895789-yqu9tNsf399hc7jjZjJVxumakwCllwuW-0-9f1120ce245a46dd64d15bef721522a5)
这样通过自执行函数就可以解决循环中创建函数的问题。但是利用ES6中let及const提供的块级作用域可以让上面写法变得更加简单。代码如下:
![](https://epubservercos.yuewen.com/D960D7/19773741008833706/epubprivate/OEBPS/Images/20_01.jpg?sign=1738895789-8BJNYnRC1zzNAgFLIX7oNVH6EY50vbkT-0-e9776566603fb0e27b923873b3380cff)
这样得到的结果就是预想的结果。由于const不能被重新赋值,所以在for循环中如果利用const来定义变量会报错。代码如下:
![](https://epubservercos.yuewen.com/D960D7/19773741008833706/epubprivate/OEBPS/Images/20_02.jpg?sign=1738895789-Xurh07k96FOPiceJ7X7ilbbG7viNtEjM-0-9a8e5658490d962c608d63d0a5288ae0)
在for-in或for-of循环中使用const时,方法与let一致,代码如下:
![](https://epubservercos.yuewen.com/D960D7/19773741008833706/epubprivate/OEBPS/Images/20_03.jpg?sign=1738895789-p8uDDsLHK6RfkTw5ro46ZsQpSKMp2Wru-0-3ea7804da4f4636d02cbdf8d1939b3bb)