預編譯
預編譯是指在程式執行之前,先對程式進行一些處理,例如預處理、編譯、連結等,以便提高程式執行效率和減少執行時的錯誤。
編譯的作用:提高程式的效率和穩定性,減少程式在執行過程中可能出現的錯誤,並提高程式的可維護性和可擴充套件性。
作用域
作用域是函式身上的屬性 [[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 }