预编译
什么是预编译?
大家可能都知道js执行的三部曲。
- 语法检析
- 预编译
- 解释执行
那么这个预编译到底是个什么呢
function test(){
console.log('a')
}
test();
这串代码能执行
test();
function test(){
console.log('a')
}
这串代码同样的也能执行,就是因为有预编译的存在,预编译会在代码执行的前一步发生,它的作用主要归于以下两点。
- 函数声明整体提升:函数不管写到哪里,都会被提到逻辑的最前面,所以不管在哪里调用,本质上都是在后面调用
- 变量 声明提升:例:var a 提升到最前面
var a = 10;
这个是变量的声明再进行赋值。预编译执行环节中,会将其拆分成var a;a=10;然后将var a;提升到逻辑的最前面。
预编译四部曲
- 创建 AO 对象 Activation Object(执行期上下文,作用是理解的作用域,函数产生 的执行空间库)
- 找形参和变量声明,将变量和形参名作为AO属性名,值为 undefined
- 将实参值和形参统一(把实参值传到形参里)
- 在函数体里面找函数声明,值赋予函数体
让我们来看一下下面这串代码
function test(a,b){
console.log(a);
console.log(b);
var b = 234;
console.log(b);
a = 123;
console.log(a);
function a(){}
var a;
b = 234;
var b = function (){}
console.log(a);
console.log(b);
}
test(1);
首先第一步,创建Ao{},第二步将变量和形参名作为Ao的属性名,如下
AO{
a:undefined,
b:undefined
}
这里要注意,预编译执行时,没有值时,值为undefined,第三步,将实参值和形参统一,此时结果为:
AO{
a:1,
b:undefined
}
第四步,找函数声明,值赋予函数体:
AO{
a:function a{},
b:undefined
}
此时预编译已经结束,可能有小伙伴要问,为什么b的值还是undefined
不应该是function (){}吗? var b = function(){} 只是声明变量b 然后将函数赋值给b ,本质上只是声明的一个变量 b ,赋值是执行的事,不归预编译管。
当预编译结束后,就会进入到解释执行环节,会到执行期上下文Ao中去找值。执行到console.log(a) 时,打印出function a{}。console.log(b) 打印出undefined 执行b=234,将Ao中b 的值赋值为234,然后打印b的值234,a=123,将Ao中的值赋值为123,打印a 的值123,b=234 将值给A0,执行b=function(){}.将值赋给AO,最后打印出 a为 123 b为function(){}
function test(a,b){
console.log(a);//f a(){}
console.log(b);// undefined
var b = 234;
console.log(b);//234
a = 123;
console.log(a);//123
function a(){}
var a;
b = 234;
var b = function (){}
console.log(a);//123
console.log(b);//f (){}
}
test(1);
相比到了这里,对js的预编译已经有了一个初步的认识了吧。