0%

2019-02-28-JS引擎解析过程-解释阶段

JS 引擎解析过程

什么是 JS 引擎?

JavaScript 解析引擎是为「读懂」JavaScript 代码,并准确地给出代码运行结果的一段程序。

举个栗子:

1
var a = 1 + 1;

JavaScript 引擎所做的事情就是看懂(解析)这段代码,并将 a 的值变成 2

JS 的解释阶段

JS 是解释型语言,所以它无需提前编译,而是由解释器实时运行的

引擎对 JS 的处理过程:

1
2
3
4
1.读取代码,进行词法分析(Lexical analysis),然后讲代码分解成词元(token)
2.对词元进行语法分析(parsing),然后将代码整理成语法书(syntax tree)
3.使用翻译器(translator),将代码转为字节码(bytecode)
4.使用字节码解释器(bytecode interpreter),讲字节码转为机器码

最终计算机执行的就是机器码。
为了提高运行速度,浏览器一般采用即时翻译(JIT-JustIn Time compiler)

即字节码只在运行时编译,用到哪一行就编译哪一行,并且把编码结果缓存(iniline cache)

这样会使整个程序的运行速度提升
而且对于不同的浏览器可能策略不同,有的浏览器为了省略了字节码的翻译过程,直接转为机器码(比如 chrome 的 v8)

总结:核心的 JIT 编译器可以将源码编译成机器码运行

JS 的预处理阶段

上述讲的解释器的整体过程,再讲一下在正式执行 JS 之前,还会有一个预处理阶段

  • 变量提升
  • 分号补全
  • 处理变量冲突
  • ···

分号补全

这个比较简单

1
2
console.log('a')
console.log('b')

JS 预处理会在后面加上分号,因为 JS 解释器有一个「Semicolon Insertion」规则,他会按照一定规则,在适当的位置补充分号

规则(不全):

  • 当有换行符的时候(包括含有换行符的多行注释),并且下一句 token 没有根前面的语法匹配时,自动添加分号。
  • 当有}时候,如果缺少分号,会添加分号
  • 程序源代码结束是,如果缺少分号,会补分号。

最终

1
2
console.log('a');
console.log('b');

举一个反例

1
2
3
4
5
6
function b() {
return
{
a: 'a'
};
}

可能你想输入的结果是:

1
{a: 'a'}

但是由于分号补全机制,最后会变成:

1
2
3
4
5
6
function b(){
return;
{
a:'a'
}
}

运行以后就是

1
undefined

变量提升

在执行过程中,可能开头没有定义变量或者函数,但是往往并没有报错。

其中包括函数提升和变量提升

1
2
3
4
5
6
7
8
a  = 1;
b();
function b(){
console.log('b');
}

var a;
b();

由于变量提升,最终结果,2 个 b()都会执行,a 会被赋值。