JS执行过程
JS 引擎有三大核心组件:解析器(Parser)、解释器(Ignition)、和编译器(TurboFan)
源码首先进入解析器,将源码经过词法分析和语法分析后解析为 AST。这个过程同时也会发生变量提升,作用域链机制也在这里体现
解释器首先将 AST 转换为字节码,然后逐行执行。这个过程同时也会生成执行上下文对象
说编译器之前,首先介绍下字节码和机器码
字节码不占空间,但是执行慢
机器码占空间,但是执行快
二者结合的方案就是 JIT(Just In Time),这时编译器就闪亮登场了
- 当 JS 引擎中的监控模块发现一段代码被多次调用,就会被标记为热代码。编译器就会将这段热代码编译为机器码缓存下来,供下次调用。提升执行效率
关于提升
为什么会出现提升
JavaScript 出现变量提升现象的原因在于在解释器执行代码前,需要根据解析器解析出来的 AST 进行执行上下文和代码解析机制,为变量、函数等声明分配内存空间
关于作用域与作用域链以及执行上下文,都有额外的文章讨论。下面着重介绍下变量提升的机制
以下内容摘自 mdn
JavaScript 提升是指解释器在执行代码之前,似乎将函数、变量、类或导入的声明移动到其作用域的顶部的过程。
发生在解析器将源码解析为 AST 之后,解释器执行代码之前。
用通俗的话来说,提升的行为主要有以下四种情形:
- 能够在声明变量之前在其作用域中使用该变量的值(函数、import)
- 能够在声明变量之前在其作用域中引用该变量而不抛出
ReferenceError
,但值始终是undefined
。(var) - 变量的声明导致在声明行之前的作用域中行为发生变化。(tdz,let const)
- 声明的副作用在评估包含该声明的其余代码之前产生。(import)
四种 function
声明的提升表现为第 1 种行为;
var
声明的提升表现为第 2 种行为;
let
、const
和 class
声明的提升表现为第 3 种行为;
import
声明的提升表现为第 1 和第 4 种行为。