![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=1738884879-Ym7M3pk1tJaOz7PnVQHQELS6hbCkan1E-0-78b95064ef782ff897b5158a030a6b66)
这段代码中,如果没有声明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=1738884879-0tR9fbjSLYuuuOFlzU752PPZl72JIADD-0-bfa0b7328fb1aed2a7838f0b3e9019be)
也就是说通过“var”声明的变量系统都会把声明隐式地升至顶部,这样的特性往往会让刚接触JavaScript及习惯其他语言的开发人员不适应,导致程序出现问题。所以针对以上情况,ES6引入了let命令来声明变量。let声明和var声明用法一致,但是不会出现变量突然提升的情况,具体代码如下:
![](https://epubservercos.yuewen.com/D960D7/19773741008833706/epubprivate/OEBPS/Images/16_03.jpg?sign=1738884879-BW58a269Oewi677aCmnDVAuyQL0YNDol-0-ab58d396bb8415b2cecf4109b90b9178)
利用let声明还可以把变量的作用域限制在代码块中,ES5中定义作用域有两种,全局作用域和函数作用域。ES5中没有块级作用域的概念,因此ES6中新增了块级作用域,用{}表示。块级作用域用于声明作用域之外无法访问的变量。主要有两种:
1)函数内部块级作用域:
![](https://epubservercos.yuewen.com/D960D7/19773741008833706/epubprivate/OEBPS/Images/16_04.jpg?sign=1738884879-ffEl8L3ASZ3Zhdf3whe8RFGSlwxKch9J-0-b893e4e413f2222f05b6f915b53152ad)
2)在字符{}之间的区域:
![](https://epubservercos.yuewen.com/D960D7/19773741008833706/epubprivate/OEBPS/Images/17_01.jpg?sign=1738884879-ankrFYWZk5UBjcrkZJHpk4SkULO2WSER-0-221b021751fe68405c68cc759faae8f4)
let在使用过程中除了上述情况外,还需要注意let声明过程中是禁止重复声明的:
![](https://epubservercos.yuewen.com/D960D7/19773741008833706/epubprivate/OEBPS/Images/17_02.jpg?sign=1738884879-EDzprbQ68XPSXWbQB8wpb7RQccAOuezW-0-14ad7b4641672c7f439ef0fd225bf59b)
1.1.2 const命令
ES6中还提供了const关键字。使用const声明的是常量,常量的值不能通过重新赋值来改变,并且不能重新声明,所以每次通过const来声明的常量必须进行初始化。
![](https://epubservercos.yuewen.com/D960D7/19773741008833706/epubprivate/OEBPS/Images/17_03.jpg?sign=1738884879-AiYTa7Qug7JlqkerqxuAPsrzHEX6nO1t-0-3dd64672239f1c37f6ba29734cc89b0d)
与其他语言不同,const在使用过程中如果声明的是对象,需要注意修改对象的属性值,但是不允许修改已经声明的对象。例如:
![](https://epubservercos.yuewen.com/D960D7/19773741008833706/epubprivate/OEBPS/Images/17_04.jpg?sign=1738884879-k9tGTWveZkudfFGc0H4Eov4SvRyzpVeS-0-3bd9dabecf5c2f00338efca924bbb6e3)
如果想让对象属性不能修改,可以借助Object.freeze函数来冻结对象,实现代码如下:
![](https://epubservercos.yuewen.com/D960D7/19773741008833706/epubprivate/OEBPS/Images/17_05.jpg?sign=1738884879-0wtP7CoVNvZQqIjn7IwxHJnmFHAs6z6a-0-4cf1c1eb0ff52b957602d59d37ff803b)
但是通过Object.freeze冻结对象需要注意不能冻结多层对象:
![](https://epubservercos.yuewen.com/D960D7/19773741008833706/epubprivate/OEBPS/Images/18_01.jpg?sign=1738884879-TuACUXGTAPmvuJj7MV7QbeHwnfNKtG1f-0-0d0a739c25a1c03a16e6487009a2ba65)
要解决多层对象的冻结问题可以通过封装一个deepFreeze函数来实现:
![](https://epubservercos.yuewen.com/D960D7/19773741008833706/epubprivate/OEBPS/Images/18_02.jpg?sign=1738884879-57V4YCIb4abp9cusCyvsfLdxIGs9B9c5-0-bcb11a068dd1235b13a99dd3aa61fa40)
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=1738884879-rRP1CWbulEtdPJ2LQUtGH3fBSsOyVdIy-0-4320e44e3662fdc44d36bcfdf7d47037)
即使通过安全的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=1738884879-tFN2lSrQ5hHLJhdneAz5sfE30lFAYwtm-0-5a6a4df570470f161447d750f70dddec)
循环执行结果并不是预想的0,1,2,3,4而是5个5,这是因为var声明在循环中作用域共用,并且会把i保存在全局作用域中。要解决循环中保存函数的问题,可以利用闭包创建独立作用域。将代码改写如下:
![](https://epubservercos.yuewen.com/D960D7/19773741008833706/epubprivate/OEBPS/Images/19_03.jpg?sign=1738884879-73mKt6wMzdfM6t4qjhcicCILldz3CyqS-0-226e6f43e525e0904271b33e2cc59edf)
这样通过自执行函数就可以解决循环中创建函数的问题。但是利用ES6中let及const提供的块级作用域可以让上面写法变得更加简单。代码如下:
![](https://epubservercos.yuewen.com/D960D7/19773741008833706/epubprivate/OEBPS/Images/20_01.jpg?sign=1738884879-KaTk41Q8bs6WfrewAhGejAj9599hTiDG-0-f4fd1d193c7d2c981d93c1cd580c4fef)
这样得到的结果就是预想的结果。由于const不能被重新赋值,所以在for循环中如果利用const来定义变量会报错。代码如下:
![](https://epubservercos.yuewen.com/D960D7/19773741008833706/epubprivate/OEBPS/Images/20_02.jpg?sign=1738884879-OjtSkWsAwfe49pTNQ0Tinn4rv9PcWeTY-0-49cd0fec26eb9b4533e333b4b9e5966e)
在for-in或for-of循环中使用const时,方法与let一致,代码如下:
![](https://epubservercos.yuewen.com/D960D7/19773741008833706/epubprivate/OEBPS/Images/20_03.jpg?sign=1738884879-UgQTy0doUlfSypPPkl9OeQIy2v0x7FIS-0-776828f5404678300b193fb1643d365a)