为什么let和const不能重复声明?为什么let和const存在暂时性死区?

2,493 阅读3分钟

前言

在面试时,面试官往往会问到varletconst的区别是什么?我想大多数人对这个问题都心有成竹,你的答案大概是以下几个方面:

  • var存在变量提升,而letconst不存在变量提升
  • var声明的变量会添加进window对象中,而letconst声明的变量不会
  • letconst声明的变量不可以重复声明
  • letconst声明的变量存在暂时性死区
  • const声明的基础类型不可修改,const声明的引用类型只能修改该引用类型的属性而不能给该变量重新赋值(const确定了一个地址,该地址不能被修改)
  • letconst存在块级作用域,而var不存在
  • let在for循环中每循环一次就会重新声明一次(因为let有块级作用域) 是不是感觉自己说得好全了,然而面试官总是喜欢坑人的,下面两个问题就是用来坑你的。

为什么let和const不能重复声明?为什么let和const存在暂时性死区?

黑人.jpg

这也太坑了吧,我TMD怎么知道?好了好了,别吐槽,我们现在就来解决这个问题。

为什么let和const不能重复声明?

在ES6规范有一个词叫做Global Enviroment Records(也就是全局环境变量记录),它里面包含两个内容,一个是Object Enviroment Record(它不等同于window对象),另一个是Reclarative Enviroment Record

  1. 函数声明和使用var声明的变量会添加进入Object Enviroment Record中。
  2. 使用let声明和使用const声明的变量会添加入Reclarative Enviroment Record中。下面是ECMAscript规范中对var,let,const的一些约束。

我们来看一下ECMAscript对var,let,const声明的约束:

QQ浏览器截图20210411214810.png

也就是说:

  • 使用var声明时,V8引擎只会检查Declarative Enviroment Record中是否有该变量,如果有,就会报错,否则将该变量添加入Object Enviroment Record中。
  • 使用letconst声明时,引擎会同时检查Object Enviroment RecordDeclarative Enviroment Record是否有该变量,如果有,则报错,否则将将变量添加入Declarative Enviroment Record中。 这就解释了为什么使用var声明的变量可以重复声明,而是用letconst声明的变量不可以重复声明。

为什么let和const存在暂时性死区?

首先我们来问一个问题,letconst声明的变量的声明真的没有提升吗?我们来做一个简单的测试。

QQ浏览器截图20210411220919.png

QQ浏览器截图20210411221000.png

可以看到,当我们使用Object.definePropertyObject Enviroment Record中添加了一个变量a(使用Object.defineProperty会在Object Enviroment Record中加入一个变量,而直接使用window.a这种方式是不会往Object Enviroment Record添加变量的)。

  • 当我们让let aObject.defineProperty同时在一个代码块中时,没有报错
  • 而当我们先执行Object.defineProperty后再用let声明a时,浏览器报错了。

其实这里就已经说明了一个问题,我想聪明的你也一定想到了。那就是let声明被提升了,但是使用let声明的变量还没有初始化,它连一个undefined的值都没有,我们使用chrome浏览器来进一步测试:

QQ浏览器截图20210411221957.png

可以看到chrome中说在初始化前无法访问a。所以说,使用letconst声明的变量的声明提升了(看起来似乎很不可思议,尽管很多书上都会说letconst不存在变量提升,但实际上提升这个词本身就是不规范的),但是没有初始化,连一个undefined的值都没有。

这就是暂时性死区出现的原因。

好了,你get到我说的内容了吗?希望本文章能帮助你更加深入理解var,let,const的区别。

以上就是我对var,let,const的区别的理解,如有错误还请指出!o( ̄▽ ̄)ブ!