在面试时,面试官往往会问到var,let,const的区别是什么?我想大多数人对这个问题都心有成竹,你的答案大概都会包含在下面:
- var存在变量提升,而let和const不存在变量提升
- var声明的变量会添加进window对象中,而let和const声明的变量不会
- let和const声明的变量不可以重复声明
- let和const声明的变量存在暂时性死区
- const声明的基础类型不可修改,const声明的引用类型只能修改该引用类型的属性而不能给该变量重新赋值(const确定了一个地址,该地址不能被修改)
- let和const存在块级作用域,而var不存在
- let在for循环中每循环一次就会重新声明一次(因为let有块级作用域)
是不是感觉自己说得好全了,然而面试管总是喜欢坑人的,下面两个问题就是用来坑你的。
为什么let和const不能重复声明?为什么let和const存在暂时性死区?
这也太坑了吧,我TMD怎么知道。好了好了,别吐槽,我们现在就来解决这个问题。
在ES6规范有一个词叫做Global Enviroment Records(也就是全局环境变量记录),它里面包含两个内容,一个是Object Enviroment Record,另一个是Declarative Enviroment Record。函数声明和使用var声明的变量会添加进入Object Enviroment Record中,而使用let声明和使用const声明的变量会添加入Declarative Enviroment Record中。下面是ECMAscript规范中对var,let,const的一些约束。
也就是说:
- 使用var声明时,V8引擎只会检查Declarative Enviroment Record中是否有该变量,如果有,就会报错,否则将该变量添加入Object Enviroment Record中。
- 使用let和const声明时,引擎会同时检查Object Enviroment Record和Declarative Enviroment Record,如果有,则报错,否则将将变量添加入Declarative Enviroment Record中。
这就解释了为什么使用var声明的变量可以重复声明,而是用let和const声明的变量不可以重复声明。
那为什么会存在暂时性死区呢?
首先我们来问一个问题,let和const声明的变量的声明真的没有提升吗?我们来做一个简单的测试。
可以看到,我们使用Object.defineProperty在Object Enviroment Record中添加了一个变量a,当我们让let a和Object.defineProperty同时在一个代码块中时,没有报错,而当我们先执行Object.defineProperty后再用let声明a时,浏览器报错了。其实这里就已经说明了一个问题,我想聪明的你也一定想到了。那就是let声明被提升了,但是使用let声明的变量还没有初始化,它连一个undefined的值都没有,我们使用chrome浏览器来进一步测试:
可以看到chrome中说在初始化前无法访问a。所以说,使用let和const声明的变量的声明提升了,但是没有初始化,连一个undefined的值都没有。
这就是暂时性死区出现的原因。
好了,你get到我说的内容了吗?希望本文章能帮助你更加深入理解var,let,const的区别。o(* ̄▽ ̄*)ブ!