在了解js预编译之前,我们要先知道 v8 引擎是怎么工作的,以及js的作用域工作原理:[具体见](url juejin.cn/post/763892…)
v8 引擎是怎么工作的
1.分词
2.语法分析得到 AST 树
3.代码生成
预编译
首先我们要知道编译发生在代码执行之前,因此js这门编程语言中就出现了声明提升这一特性。
console.log(a);
var a = 1;
在js中这份代码并不会报错,而是输出 undefined。这就是因为声明提升,在编译时代码会变成
var a;
console.log(a);
a = 1;
那么在知道js有声明提升这个概念后,我们就想知道它为什么会出现声明提升,这就是预编译带来的结果。
预编译分为函数体内的预编译和全局的预编译
函数体内的预编译
函数体内的预编译分为四步:
1.创建一个执行上下文 AO:{}
2.找形参和变量声明,将形参和变量名作为属性名,添加到 AO 中,值为 undefined
3.将形参和实参统一
4.在函数体内找函数声明,将函数名作为 AO 中的属性名,函数体作为属性值
function fn(a){
console.log(a);
var a = 123;
console.log(a);
function a(){};
var b = function(){};
console.log(b);
function c(){};
var c = a;
console.log(c);
}
fn(1);
例如上面这份代码,它的预编译过程就为:
创建一个对象
AO = {
}
然后找形参和变量声明,代码中的形参为 a,变量声明有 var a , var b , var c ,将这些添加到 AO 中,值为 undefined
AO = {
a: undefined,
b: undefined,
c: undefined
}// 如果属性名相同,那么用后面值的覆盖前面的值
接着将形参和实参统一
AO = {
a: 1,
b: undefined,
c: undefined
}
最后在函数体内找函数声明,函数声明有 function a(){} 和 function c(){} ,然后将函数名作为 AO 中的属性名,函数体作为属性值
AO = {
a: function(){},
b: undefined,
c: function(){}
}
这就是函数体内的预编译后的结果。
然后就是代码执行
function fn(a){
console.log(a); // function(){}
var a = 123
console.log(a); // 123
function a(){}
var b = function(){}
console.log(b); // function(){}
function c(){}
var c = a
console.log(c); // 123
}
执行结果为
全局的预编译
全局的预编译分为三步:
- 创建全局执行上下文 GO:{}
- 找全局变量声明,将全局变量名作为属性名,添加到 GO 中,值为 undefined
- 找全局函数声明,将函数名作为 GO 的属性名,函数体作为属性值
var a ;
var b = 2;
function a () {
console.log(a);
var c = 3;
var a = b;
function c() {};
console.log(c);
}
a();
console.log(a);
以上面这个代码为例: 首先创建 GO:{}
GO = {
}
然后找全局变量,有 var a 和 var b ,添加到 GO 中,值为 undefined
GO = {
a: undefined,
b: undefined
}
最后找全局函数声明,有 function a(){} ,添加到 GO 中
GO = {
a: function(){},
b: undefined
}
这就是全局的预编译。 然后就是执行,执行过程中遇到 a() ,即调用了 函数体 a ,接着就进行 函数体内的预编译
AO = {
c: function(){},
a: undefined
}
然后继续执行
var a ;
var b = 2;
function a () {
console.log(a); // undefined
var c = 3;
var a = b;
function c() {};
console.log(c); // 3
}
a();
console.log(a); // function(){}
最后运行结果为:
总结
JavaScript 在执行代码之前会进行预编译,将变量和函数声明提升到作用域顶部。函数体预编译创建 AO 对象,全局预编译创建 GO 对象,这一机制正是 JavaScript「声明提升」现象的根源。