前言
最近在看《YOU DON’T KNOW JS》一书,里面讲到JS的编译原理,只是宏观和简单的介绍了一下,于是自己写了此文,一来总结文中所讲的传统语言的编译和JS的编译原理,二来扩展一下我理解的编译原理
正文
传统编译语言的编译原理
在传统的编译语言中,编译分三步
- 词法分析
首先编译器会把代码分解成有意义的词法单元
- 语法分析
接着,将词法单元组成的词法单元流(数组)解析成一个由元素逐级嵌套所组成的代表了程序语法结构的树。这个树被称为“抽象语法树”(Abstract Syntax Tree,AST)
3. 代码生成
最后过程,将上面解析好的AST转换为可执行代码。说白了,就是通过某种方法可以将AST 转化为一组机器指令
我将上述过程绘制如下图:
JS的编译原理
JS引擎进行编译的步骤与传统编译语言非常相似,但比起那些编译只有三步的语言来说JS引擎要复杂的多。例如,在词法分析和代码生成阶段有特定的步骤来对运行性能进行优化,包括对冗余元素进行优化等
而且,对于JS来说,大部分情况下编译发生在代码执行前的几微秒(甚至更短)的时间内
简单来说,任何 JS代码片段在执行前都要进行编译
我理解的JS编译原理
要理解JS的编译原理,其实得回顾JS是如何运行的?
我将它JS运行分三个步骤
- 词法、语法分析
- 预编译
- 解释执行
通常JS在执行代码前,系统会先执行词法和语法分析,通篇扫描一遍看是否有语法错误,有错误,程序终止,没有错误就会走到预编译环节
预编译发生在函数执行前的前一刻,具体过程分四步:
1.创建AO对象;(Active Object,执行期上下文)
2.找形参和变量声明,将变量名和形参名作为AO对象的属性名,值为undefined;
3.将实参和形参相统一;
4.在函数体里面找函数声明(不包括函数表达式),将函数声明的名作为AO对象的属性名挂起,值为该函数。
在全局开始执行的前一刻,会发生全局预编译,生成的对象是GO(Global Object)
预编译执行完才会开始解释执行代码,读一行执行一行,读一行执行一行。在读的过程,就会将代码变成可执行代码
整个过程简单绘制如下:
可以看到,与传统的编译相比,JavaScript引擎有个很大的特点就是多了一个预编译的环节。预编译之后也是通过引擎将代码解析成可执行代码,然后执行代码
这就是JS引擎的运行过程和原理
参考资料
《YOU DON’T KNOW JS》
备注
新手小白,加上第一次发文,难免有跑偏。有理解不正确的,希望批评指出,我会及时更正,感谢!!