因为说let没有变量提升,我被嘲笑了
最近在和同事闲聊var和let的区别时,我被嘲笑了,起因是我提出了var具有变量提升的特性而let没有的观点。在我看来这不是最常刷到的面试题吗?但是在一番仔细研究之后我发现事情并不是我想象的这样,即let同样存在变量提升,只是let存在暂时性死区。变量提升证明var声明存在变量提升
通常我们是这样子来证明var存在变量提升的。functionfn(){console。log(a)undefinedvara12}fn()复制代码
为什么这段代码会输出undefined,而不是报错呢?
原因就是js在创建执行上下文时,会检查代码,找出变量声明和函数声明,并将函数声明完全存储在环境中,而将通过var声明的变量设定为undefined,这就是所谓的变量提升。从字面上理解就是变量和函数声明会被移动到函数或者全局代码的开头位置。
那么当我们将var替换为let时,结果又会如何?functionfn(){console。log(a)UncaughtReferenceError:aisnotdefinedleta12}fn()复制代码
意料之中,代码报错了。很多人通过这个反例,便认为let没有变量提升,但其实这是错误的。上面举的例子只能证明,var存在变量提升,但是并不能证明let不存在变量提升。证明let声明存在变量提升
我们再举一个例子:varxparentvalue;(function(){console。log(x);parentvalue}())复制代码
代码会输出parentvalue,原因很简单,涉及到了作用域链的知识。在匿名函数作用域中没有找到x变量,便会沿着作用域链,找到父级作用域,然后便再父级作用域中找到了x变量,并输出。
接着我们在匿名函数中,加入let进行变量声明,此时结果会是如何呢?varxparentvalue;(function(){console。log(x);UncaughtReferenceError:xisnotdefinedletxchildvalue}())复制代码
想不到吧!此时的代码又会报错了,从这里其实可以看出let也是存在变量提升的,知识在变量显式赋值之前不能对变量进行读写,否则就会报错,这也就是所谓的let和const的暂时性死区。
暂时性死区(TemporalDeadZone)
引用MDN上的定义
letbindingsarecreatedatthetopofthe(block)scopecontainingthedeclaration,commonlyreferredtoashoisting。Unlikevariablesdeclaredwithvar,whichwillstartwiththevalueundefined,letvariablesarenotinitializeduntiltheirdefinitionisevaluated。AccessingthevariablebeforetheinitializationresultsinaReferenceError。Thevariableisinatemporaldeadzonefromthestartoftheblockuntiltheinitializationisprocessed。
大概意思便是let同样存在变量提示(hoisting),只是形式与var不同,var定义的变量将会被赋予undefined的初始值,而let在被显式赋值之前不会被赋予初始值,并且在赋值之前读写变量都会导致ReferenceError的报错。从代码块(block)起始到变量求值(包括赋值)以前的这块区域,称为该变量的暂时性死区。varxparentvalue;(function(){letx此时暂时性死区开始console。log(x);UncaughtReferenceError:xisnotdefined暂时性死区结束letxchildvalue}())复制代码总结
事实证明let和var同样存在变量提升,而且let声明还具有暂时性死区的概念。
作者:37。2同志
链接:https:juejin。cnpost6983702070293430303
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。