你可能不知道的JavaScript 前端开发那些事儿

深入编译原理

2021-02-05  本文已影响0人  深度剖析JavaScript
前言

最近在看《YOU DON’T KNOW JS》一书,里面讲到JS的编译原理,只是宏观和简单的介绍了一下,于是自己写了此文,一来总结文中所讲的传统语言的编译和JS的编译原理,二来扩展一下我理解的编译原理

传统编译语言的编译原理

在传统的编译语言中,编译分三步

  1. 词法分析

首先编译器会把代码分解成有意义的词法单元

  1. 语法分析

接着,将词法单元组成的词法单元流(数组)解析成一个由元素逐级嵌套所组成的代表了程序语法结构的树。这个树被称为“抽象语法树”(Abstract Syntax Tree,AST

  1. 代码生成

最后过程,将上面解析好的AST转换为可执行代码。说白了,就是通过某种方法可以将AST转化为一组机器指令

我将上述过程绘制如下图:

JS的编译原理

JS引擎进行编译的步骤与传统编译语言非常相似,但比起那些编译只有三步的语言来说JS引擎要复杂的多。例如,在词法分析和代码生成阶段有特定的步骤来对运行性能进行优化,包括对冗余元素进行优化等

而且,对于JS来说,大部分情况下编译发生在代码执行前的几微秒(甚至更短)的时间内

简单来说,任何JS代码片段在执行前都要进行编译

我理解的JS编译原理

要理解JS的编译原理,其实得回顾JS是如何运行的?
我将它JS运行分三个步骤

  1. 词法、语法分析
  2. 预编译
  3. 解释执行

通常JS在执行代码前,系统会先执行词法和语法分析,通篇扫描一遍看是否有语法错误,有错误,程序终止,没有错误就会走到预编译环节

预编译发生在函数执行前的前一刻,具体过程分四步:
1.创建AO对象;(Active Object,执行期上下文)
2.找形参和变量声明,将变量名和形参名作为AO对象的属性名,值为undefined
3.将实参和形参相统一;
4.在函数体里面找函数声明(不包括函数表达式),将函数声明的名作为AO对象的属性名挂起,值为该函数。

在全局开始执行的前一刻,会发生全局预编译,生成的对象是GO(Global Object)

预编译执行完才会开始解释执行代码,读一行执行一行,读一行执行一行。在读的过程,就会将代码变成可执行代码

整个过程简单绘制如下:

可以看到,与传统的编译相比,JavaScript引擎有个很大的特点就是多了一个预编译的环节。预编译之后也是通过引擎将代码解析成可执行代码,然后执行代码

这就是JS引擎的运行过程和原理

参考资料
《YOU DON’T KNOW JS》

上一篇下一篇

猜你喜欢

热点阅读