切換語言為:簡體

JavaScript的預編譯過程分析

  • 爱糖宝
  • 2024-10-09
  • 2044
  • 0
  • 0

預編譯

預編譯是指在程式執行之前,先對程式進行一些處理,例如預處理、編譯、連結等,以便提高程式執行效率和減少執行時的錯誤。

編譯的作用:提高程式的效率和穩定性,減少程式在執行過程中可能出現的錯誤,並提高程式的可維護性可擴充套件性

作用域

作用域是函式身上的屬性 [[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();

作用域鏈

JavaScript的預編譯過程分析

分析

全域性定義了函式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();

預編譯的分析(重點!)

定義

  • 發生在全域性:

  1. 建立GO物件

  2. 找變數宣告,將變數名作為GO的屬性名,值為undefined

  3. 在全域性找函式宣告,將函式名作為GO的屬性名,值為該函式體

  • 發生在函式體內:

  1. 建立一個AO物件

  2. 找形參和變數宣告,將形參和變數名作為AO的屬性名,值為undefined

  3. 形參和實參統一

  4. 在函式體內找函式宣告,將函式名作為AO的屬性名,值為該函式體

步驟

全域性預編譯-->GO-->執行,碰見函式-->函式預編譯-->AO-->執行函式

例項一

程式碼

var a = 1;
function fn(a) {
    var a = 2;
    function a() {};
    console.log(a);
}

fn(3);

分析

  • 首先進行全域性預編譯-->GO

  1. GO:{ }

  2. GO:{ a:undefined }

  3. GO:{ a:undefined , fn:function(a){ var a = 2; function a() {}; console.log(a); }

  • 執行

  1. GO:{ }

  2. GO:{ a:1 }

  3. GO:{ a:undefined , fn:function(a){ var a = 2; function a() {}; console.log(a); }

  • 碰見函式,進行函式預編譯-->AO

  1. AO:{ }

  2. AO:{ a:undefined;(這裏是a:undefined;(形參)a:undefined;(變數)) }

  3. AO:{ a:3(fn(3)), }

  4. AO:{ a:function(){}, (a:3;a:function(){};最後得出的結果) }

  • 執行函式

    AO:{ a:2, }

JavaScript的預編譯過程分析

例項二

程式碼

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
    
}

0則評論

您的電子郵件等資訊不會被公開,以下所有項目均必填

OK! You can skip this field.