var a=2当我们看到这段代码时,问:这个段代码的做了什么?
我们可能会回答:定义一个变量,并给这个变量赋值。对于表面的话是这样的。但是更深层次的理解是如何的,是否思考过?现在,这篇文章来讨论这个问题。
编译阶段
首先它会经历三个过程:
- 分词/词法分析阶段
- 解析/语法分析阶段
- 代码(机器码)的生成阶段
接下来我们细化分析这几个过程:
分词/词法分析阶段(token)
当浏览器执行JS脚本的时候,首先会按代码顺序加载由标签分割的代码块,这个时候的代码块只是字符串,这个过程将这些字符串分解成有意义的代码块,根据词法分析规则将var a=2分割成var,a,=,2,这几个代码块称为词法单元(Token)
解析/语法分析阶段(Parsing)
这个过程是将词法单元流(数组)转换成一个由元素逐级嵌套所组成的代表了程序语法
结构的树。这个树被称为“抽象语法树”(Abstract Syntax Tree,AST)。
var a = 2; 的抽象语法树中可能会有一个叫作 VariableDeclaration 的顶级节点,接下
来是一个叫作 Identifier(它的值是 a)的子节点,以及一个叫作 AssignmentExpression
的子节点。AssignmentExpression 节点有一个叫作 NumericLiteral(它的值是 2)的子
节点。
——《你所不知道的javascript》
在这个阶段和css解析一样,css解析根据解析规则解析成DOM树。要是还觉得不够形象,推荐一个网站resources.jointjs.com/demos/javas…
拿var a=2;解析出来的Abstract Syntax Tree为:
对于这个图的理解:拿到每个token根据构建规则来构建AST。这个过程也可以理解成将源码转换为AST的过程。
代码生成
当编译器进行代码生成的时候,这个程序会和预期的的有所不同。
1. 在该作用域空间中会创建一个AO对象(Activation Object)执行上下文。
2. 变量的声明,并在AO对象中设置对应的属性名。
在这个过程会为我们下一个执行阶段做好铺垫。
V8引擎对AST(抽象语法树)的优化
在这个过程:V8对机器码的生成做了优化,让代码生成阶段提高了效率。
相比其它的JavaScript的引擎AST转换成字节码再到机器码,V8将其直接编译成原生机器码,并且使用了如内联缓存(inline caching)等方法来提高性能。
执行阶段
首先拿到处理的代码a=2,判断操作类型,然后按操作规则执行。
**解析:**a=2;
-
引擎先通过LHS查询(LHS查询:赋值操作左侧的查询,LHS查询试图找到变量的容器本身,从而对其赋值。)找到变量a的位置。
-
在通过RHS查询(RHS查询:赋值操作右侧的查询,可以理解为“取到某某的值”)
-
将找到的值赋给变量a