诸如 C / C++ / JAVA 等语言,都有对应的编译器,而编译器会将这些高级语言编译成目标机(目标系统,如Windows, Linux, Unix等)可执行程序。
这些语言的编译器工作流程如下:
- 词法分析;
- 语法分析;
- 语义分析 & 中间代码生成;
- 优化(中间代码);
- 目标代码生成;
注:
- C / C++ 这类语言是直接编译成二进制可执行文件;
- JAVA是编译成JVM(JAVA虚拟机)可执行文件
但是,JS通常被归为『动态』或『脚本』或『解释执行』语言,因此,JS不会提前编译,通常只有在代码执行前才会开始编译(几微秒甚至更短!),这也就是为什么JS可以跨平台运行(只要系统中有浏览器就行)。当然,JavaScript引擎非常复杂,想了解的话直接看源码吧。
那么,在短短的几微秒甚至更短的时间里,JS引擎对代码编译发生了哪些事呢?
JS引擎编译工作流程如下:
- 分词/词法分析;
- 解析/语法分析;
- 代码生成;
// 代码
var a = 2;
分词/词法分析的工作:
var、a、=、2 、; 共5个词【又叫做:词法单元流(数组)】解析/语法分析的工作:
将词法单元流解析成一棵树,这个树叫做:AST(Abstract Syntax Tree 抽象语法树),这棵树可能如下图所示(对于这个例子来说)
- 代码生成:
JS引擎将AST转换为可执行的代码,这个过程与语言、目标平台相关;简单的说:就是创建一个变量a,分配内存,并将值(2)存储到变量a中。
比起那些编译过程只有三个步骤的语言的编译器,JavaScript 引擎要复杂得多。例如,在 语法分析和代码生成阶段有特定的步骤来对运行性能进行优化,包括对冗余元素进行优化等。
因此在这里只进行宏观、简单的介绍:
- 首先,JavaScript 引擎不会有大量的(像其他语言编译器那么多的)时间用来进行优化,因 为与其他语言不同,JavaScript 的编译过程不是发生在构建之前的。
- 对于 JavaScript 来说,大部分情况下编译发生在代码执行前的几微秒(甚至更短!)的时 间内。在我们所要讨论的作用域背后,JavaScript 引擎用尽了各种办法(比如 JIT,可以延 迟编译甚至实施重编译)来保证性能最佳。
- 简单地说,任何 JavaScript 代码片段在执行前都要进行编译(通常就在执行前)。因此, JavaScript 编译器首先会对 var a = 2; 这段程序进行编译,然后做好执行它的准备,并且 通常马上就会执行它。