了解预编译之前,我们先来看下AO和GO的概念
AO(Actived Object)活动对象:保存函数调用时的变量、函数的集合
当函数执行时,会创建一个称为执行期上下文的内部对象(AO)。一个执行期上下文定义了一个函数执行时的环境,函数每次执行时的执行上下文都是独一无二的,函数每次执行时,都会把新生成的执行期上下文,填充到作用域链的最顶端。当函数执行完毕,它所产生的执行上下文被销毁。
GO(Global Object)全局对象:GO和AO差不多,只不过是保存window对象的变量、函数的集合
预编译有什么用:
- 分析脚本的执行顺序
- 预编译简单理解就是在内存中开辟一些空间,存放一些变量与函数
- 理解预编译对大家理解作用域同样有帮助
预编译什么时候发生:
预编译在函数执行前发生
预编译的执行流程:
- 创建AO对象
- 找形参和变量声明,将变量和形参作为AO属性名,值为undefined
- 将实参值和形参统一,实参值赋给形参
- 在函数体里面找函数声明,值赋予函数体
接下来,看一个例子:
function test(a){
console.log(a);//function a(){}
var a = 123;
console.log(a);//123
function a(){
function xxx(){};
};
console.log(a);//123
var b = function(){};
console.log(b) ;//function (){}
}
test(1);
预编译:
1.找形参和变量声明,将变量和形参作为AO属性名,值为undefined
AO{
a:undefined;
b:undefined;
}
2.将实参值和形参统一,实参值赋给形参
AO{
a:1;
b:undefined;
}
3.在函数体里面找函数声明,值赋予函数体
AO{
a:function a(){};
b:undefined;
}
预编译完后,开始执行test函数
第一次打印a,从AO中找到的是function a(){}
第二次打印a,a被赋值成123,相当于AO中的a发生了变化,找到的就是123
第三次打印a,可能会有点疑问,为什么不是function a(){}呢?因为在预编译最后一步函数声明整体提升(具体点说,无论函数调用和声明的位置是前是后,系统总会把函数声明移到调用前面) ,可以理解成函数声明整体提升执行过了,再碰到就不用再次提升。所以AO中的a没有变化,找到的还是123
最后打印b,b被赋值为匿名函数,AO中的b变成function (){},找到的就是function (){}