预编译
预编译是指在程序运行之前,先对程序进行一些处理,例如预处理、编译、链接等,以便提高程序运行效率和减少运行时的错误。
编译的作用:提高程序的效率和稳定性,减少程序在运行过程中可能出现的错误,并提高程序的可维护性和可扩展性。
作用域
作用域是函数身上的属性 [[scope]](给js引擎访问的,我们拿不到 -- 隐式属性),用于存储函数中的有效标识符。
作用域链
作用域是执行期上下文对象的集合,这种集合呈链式连接,我们把这种链关系称之为作用域链。
- GO (Global Object):函数执行上下文对象;
- AO (Activation Object):全局执行上下文对象;(可访问GO)
代码
function a() {
function b(){
var b = 22;
console.log(a);
};
var a = 111;
b();
};
var glob = 100;
a();
作用域链
分析
全局定义了函数a和global,形成如图GO,此时a[[scope]]的0指向GO,函数a内定义了函数b和a,形成如图AO,此时a[[scope]]的0指向自己的AO,1指向GO,函数b定义了b,形成如图AO,b[[scope]]的0指向自己的AO,1指向a[[scope]]。
声明提升
- 变量声明,声明提升(上一篇文章提到过)
- 函数声明,整体提升
test();
function test() {
var a = 123;
console.log(a);
}
上述代码相当于:
// 函数声明提升
function test() {
var a = 123;
console.log(a);
}
test();
预编译的分析(重点!)
定义
- 发生在全局:
- 创建GO对象
- 找变量声明,将变量名作为GO的属性名,值为undefined
- 在全局找函数声明,将函数名作为GO的属性名,值为该函数体
- 发生在函数体内:
- 创建一个AO对象
- 找形参和变量声明,将形参和变量名作为AO的属性名,值为undefined
- 形参和实参统一
- 在函数体内找函数声明,将函数名作为AO的属性名,值为该函数体
步骤
全局预编译-->GO-->执行,碰见函数-->函数预编译-->AO-->执行函数
实例一
代码
var a = 1;
function fn(a) {
var a = 2;
function a() {};
console.log(a);
}
fn(3);
分析
首先进行全局预编译-->GO
- GO:{ }
- GO:{ a:undefined }
- GO:{ a:undefined , fn:function(a){ var a = 2; function a() {}; console.log(a); }
- 执行
- GO:{ }
- GO:{ a:1 }
- GO:{ a:undefined , fn:function(a){ var a = 2; function a() {}; console.log(a); }
碰见函数,进行函数预编译-->AO
- AO:{ }
- AO:{ a:undefined;(这里是a:undefined;(形参)a:undefined;(变量)) }
- AO:{ a:3(fn(3)), }
- AO:{ a:function(){}, (a:3;a:function(){};最后得出的结果) }
- 执行函数
AO:{ a:2, }
实例二
代码
function fn() {
console.log(a);//function a(){}
var a = 123;
console.log(a);//123
function a() {};
console.log(a);//123
var b = function(){};
console.log(b);//function b(){}
function c(){};
var c = a;
console.log(c);//123
}
fn(1);
分析
GO:{
fn:function fn(){}
}
AO:{
a:undefined-->undefined-->1-->function a(){}, -->123,
b:undefined, -->function b(){},
c:undefined-->function c(){}, -->123
实例三
代码
function test(a, b) {
console.log(a);//1
c = 0
var c;
a = 3
b = 2
console.log(b);//2
function b() {}
console.log(b);//2
}
test(1)
分析
GO:{
test:function
}
AO:{
a:undefined-->1, -->3
b:undefined-->undefined-->function b(){}, -->2
c:undefined, -->0
}