js 預編譯


js 運行代碼的時候分為幾個步驟:語法分析 ==》預編譯  ==》解釋執行

語法解析:通篇掃描代碼,查看語法是否出錯

解釋執行讀一行 - 解釋一行 - 執行一行

 

預編譯執行的操作:

// 假設之前並沒有定義a
console.log(a);

打印結果:Uncaught ReferenceError: a is not defined

這個大家應該都知道:在變量未定義時就對變量進行訪問就會報錯(typeof 列外)

 

再看一個例子:

1 // 假設之前並沒有定義變量a
2 console.log(a);
3 
4 var a = 123;
5 
6 console.log(a);

看上面代碼會打印什么?會不會報錯?

打印結果:

undefined
123

為什么這個沒有報錯:因為在預編譯的時候對變量進行了提升即變量提升。 定義的變量的聲明(var a ;)被提到了代碼塊的最前面,變量的賦值操作(a = 123)沒有變化。

所以被編譯后就相當於

1 // 假設之前沒有定義變量a
2 var a;
3 
4 console.log(a);
5 
6 a = 123;
7 
8 console.log(a);

 

看下面這個例子:

 1 // 假設之前沒有定義test
 2 console.log(test);
 3 
 4 var test = 123; 
 5 
 6 function test () {
 7 
 8 }
 9 
10 console.log(test);

打印結果:

function test () {}
123

為什么第二行的輸出的不是undefined 了?執行步驟是什么樣子的?

因為函數聲明在編譯的時候也會進行提升,叫做函數提升

執行步驟:

1、變量提升:var test; 提升到最前面。此時test = undefined;

2、函數提升:function test () {}; 提升到最前面並覆蓋var test; 的聲明。所以第二行打印function test () {}; 此時test = function test () {}

3、進行賦值操作 test = 123; 此時test = 123;

 

 1 function test (test) {
 2   console.log(test);  // function test(){var a = 789}
 3    var test = 123;
 4    function test () {
 5        var a = 789;
 6     };
 7    console.log(test) ;  // 123     
 8 }
 9 
10 test(456);

Why?

 

變量提升和函數提升是如何實現的?

預編譯執行步驟

(a) 函數內

 1、在代碼定義之后執行之前生成活動對象AO(Activation Object ) 空對象{}

 2、查找函數體內的形參和變量,定義為AO的屬性,賦值為undefined;

 3、將實參跟形參統一,即把實參賦值給AO[形參]

 4、查找函數里的函數聲明,將函數聲明賦值給AO 即 AO[函數名] = 函數

(b) 全局

 1、在代碼定義之后執行之前生成全局環境對象GO(Global variable Object ) 空對象{}

 2、查找變量,定義為GO的屬性,賦值為undefined;

 3、查找函數聲明,將函數聲明賦值給GO 即 GO[函數名] = 函數;

 

以上面的例子分析預編譯過程:

function test (test) {
   console.log(test);  // function test(){var a = 789}
    var test = 123;
    function test () {
        var a = 789;
     };
    console.log(test) ;  // 123     
 }
 
test(456);

var a = 111;

/** 全局 **/
// 第一步:創建GO // GO{}; // 第二步:查找變量定義為GO的屬性,賦值為undefined;
// GO{
// a: undefined
// };
// 第三步:將函數聲明賦值給GO
// GO{
// a: undefined,
// test: function test(test) {...}
// }

/** function test(test){...} 函數內 **/
// 第一步: 創建AO
// AO {}
// 第二步: 查找形參和變量,定義為AO的屬性, 賦值為undefined;
// AO {
// test: undefined
// }
// 第三步: 形參和實參統一
// AO {
// test: 456
// }
// 第四步:將函數聲明給AO
// AO {
// test: function test() { var a = 789 }
// }

 

之后就是一步一步的執行代碼了

function test (test) {
   console.log(test);  // function test(){var a = 789}
    var test = 123;
    function test () {
        var a = 789;
     };
    console.log(test) ;  // 123     
 }
 
test(456);

var a = 111;

// test(456); 進入到function test (test) {...} 內部
// console.log(test); // 打印 function test(){var a = 789}
// var test = 123; 由於 test 變量的聲明已經提升,所以這句只執行 test = 123; 即AO[test] = 123
// AO {
//   test: 123
// }
// function test() {var a = 789} 已經提升
// console.log(test) //打印 123
// 退出function test (test) {...} 銷毀AO
// var a = 111; 由於 a 變量已經提升,這句只執行賦值 a = 111; 即 GO[a] = 111;
// GO{
//   a: 111,
//   test: function test(test) {...}
// }

// 當頁面銷毀時銷毀GO

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM