es6如何实现块级作用域?为什么let和const会有暂时性死区(TDZ)?

471 阅读2分钟

题目一:

  1. js是怎么执行的?

就是一个调用栈的过程,执行js的时候进行入栈和出栈的过程,栈底始终是全局执行上下文(window或global);

  1. 那每一个执行上下文中有哪些模块呢?

2.1 :变量环境

变量环境中存放var声明的变量,每进行一次入栈操作,都会为这个入栈函数分配一片环境变量存放var声明的变量。

2.2:词法环境(栈的数据结构)

  • 词法环境存放let和const声明的变量或常量,栈底存放的是外层let或const变量 var1,遇到for等使用let或const再将let或const声明的var2变量压栈。

  • for循环执行完后var2出栈,函数执行完后var1出栈。

示例:



function foo(){

    var a = 1

    let b = 2

    {

      let b = 3

      var c = 4

      let d = 5

      console.log(a)

      console.log(b)

    }

    console.log(b) 

    console.log(c)

    console.log(d)

}   

foo()

2.3:this

2.4:outer

题目二:

  1. var声明的变量会有变量声明提升,起提升后初始化默认赋值为undefined

  2. 思考:那let和const声明的变量在块级作用域内会提升吗?

2.1:其实应该是会的,如“你不知道的javascript”上卷中说到,在语言的词法分析阶段,就可以会变量做声明提升的优化,减少编译和执行时的工作量,达到性能优化的效果。

2.2:那为什么在声明前调用let或const变量会报(TDZ)错误呢?

2.3:因为使用let和const声明的变量不会在变量声明提升是初始化复制undefined

2.4:思考?

既然let和const声明的变量在提升后没有赋值undefined,这时候let和const声明的变量在内存地址中存的是什么?

答案一:是不是什么也没存

答案二:上次使用这片内存,但已经没有被引用的数据。

思考:那这时候我们把这些数据读出来合适吗?

如果读出来了,那读出来的是什么数据呢?js是否能识别(js读取不同的类型的数据,是有不同的识别机制的,比如读取的对象,那对象的内存地址前三位都必须为0)

情况1: 如果数据不符合js数据存储的规范,那读出来的数据是不是就紊乱了?

情况2: 如果符合js存储数据的规范,那也会导致数据不对。

基于上面的这些情况,所以引入的let和const的暂时性死区(TDZ)