预编译
预编译是指在程序运行之前,先对程序进行一些处理,例如预处理、编译、链接等,以便提高程序运行效率和减少运行时的错误。
编译的作用:提高程序的效率和稳定性,减少程序在运行过程中可能出现的错误,并提高程序的可维护性和可扩展性。
作用域
作用域是函数身上的属性 [[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 }