let到底有没有变量提升?

106 阅读2分钟
console.log(x); // ReferenceError let x = 10;

暂时性死区

JavaScript中暂时性死区(Temporal Dead Zone)、
let声明的变量x会被提升到当前作用域顶部,但是不会进行初始化。

在初始化赋值前,变量x处在一个暂时性死区中,无法被访问。
第一行代码试图访问x,由于还未初始化就出错了。

当执行流运行到let x语句时,对x进行初始化赋值,死区结束。
这时x才能被安全访问,不会产生引用错误。

所以暂时性死区指的是:
let/const变量在声明位置之前的区域,变量存在但无法被引用,读取会抛错。
而var变量就可以在声明位置之前的区域访问,也就是所谓的变量提升

js内部代码是怎么被执行的

  • 编译器负责编译代码,进行词法分析、语法分析等,生成执行引擎可执行的字节码或中间代码。
  • 执行引擎加载编译结果,在运行时解释执行代码,管理运行上下文。
  • 作用域定义了变量和函数的访问范围,执行引擎会基于作用域链来查找标识符。

变量的三个阶段

  • 声明阶段 - 在作用域中注册变量,这时变量不存在绑定。
  • 初始化阶段 - 为变量在作用域中分配内存,创建变量绑定,并将变量自动初始化为 undefined。
  • 赋值阶段 - 将一个值赋给已初始化的变量。

在编译阶段,编译器会进行预处理:

  • var、let和const声明的变量会在声明阶段提升到当前作用域顶部进行注册
  • var变量会在初始化阶段初始化为undefined
  • let和const变量不会在这个阶段初始化

在执行阶段,引擎会逐行解释执行代码:

  • 对var的访问可以在作用域顶部找到并返回undefined
  • 对let和const的访问会抛出错误,因为还未初始化,也就是所谓的ReferenceError
  • 当执行到let/const声明语句时:
    • 在当前作用域中初始化并赋值变量
    • 这时才可以正确访问let和const变量

但是因为暂时性死区的存在看起来没有变量提升,其实说const和let没有变量提升也没什么问题,本质上还是明白,不能在let和const之前访问它们声明的变量。