为什么let和const不能重复声明?为什么let和const存在暂时性死区?
前言
在面试时,面试官往往会问到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怎么知道?好了好了,别吐槽,我们现在就来解决这个问题。
为什么let和const不能重复声明?
在ES6规范有一个词叫做Global Enviroment Records
(也就是全局环境变量记录),它里面包含两个内容,一个是Object Enviroment Record
(它不等同于window对象),另一个是Reclarative Enviroment Record
。
- 函数声明和使用
var
声明的变量会添加进入Object Enviroment Record
中。 - 使用
let
声明和使用const
声明的变量会添加入Reclarative Enviroment Record
中。下面是ECMAscript规范中对var
,let
,const
的一些约束。
我们来看一下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存在暂时性死区?
首先我们来问一个问题,let
和const
声明的变量的声明真的没有提升吗?我们来做一个简单的测试。
可以看到,当我们使用Object.defineProperty
在Object Enviroment Record
中添加了一个变量a
(使用Object.defineProperty
会在Object Enviroment Record
中加入一个变量,而直接使用window.a这种方式是不会往Object Enviroment Record
添加变量的)。
- 当我们让
let a
和Object.defineProperty
同时在一个代码块中时,没有报错 - 而当我们先执行
Object.defineProperty
后再用let
声明a
时,浏览器报错了。
其实这里就已经说明了一个问题,我想聪明的你也一定想到了。那就是let
声明被提升了,但是使用let
声明的变量还没有初始化,它连一个undefined
的值都没有,我们使用chrome浏览器来进一步测试:
可以看到chrome中说在初始化前无法访问a
。所以说,使用let
和const
声明的变量的声明提升了(看起来似乎很不可思议,尽管很多书上都会说let
和const
不存在变量提升,但实际上提升这个词本身就是不规范的),但是没有初始化,连一个undefined
的值都没有。
这就是暂时性死区出现的原因。
好了,你get到我说的内容了吗?希望本文章能帮助你更加深入理解var
,let
,const
的区别。
以上就是我对var,let,const的区别的理解,如有错误还请指出!o( ̄▽ ̄)ブ!