JavaScript解析機制是什么?
JavaScript解析過程分為兩個階段,一個是編譯階段,另外一個就是執行階段。
* 編譯階段
編譯階段就是我們常說的JavaScript預解析(預處理)階段,在這個階段JavaScript解釋器將完成把JavaScript腳本代碼轉換到字節碼。
* 執行階段
在編譯階段JavaScript解釋器借助執行環境把字節碼生成機械碼,並順序執行。
編譯階段(預解析階段)做什么操作?
* var , function聲明的變量提升
首先,創建一個當前執行環境下的活動對象,然后將用 var 聲明的變量設置為活動對象的屬性(也就是將其添加到活動對象當中)並將其賦值為undefined,然后將 function 定義的函數 也添加到活動對象當中。
1 if( false ){ 2 var aa = 20; 3 var bb = 30; 4 } 5 6 function AA(){}; 7 function BB(){}; 8 9 //var定義的aa,bb以及function定義的AA(),BB()都會被變量提升到window對象下面
* 函數聲明與函數表達式在預解析的區別
首先,我們知道解析器會對function定義的函數(也就是函數聲明)在代碼開始執行之前對其實行函數聲明提升(function declaration hoisting),所以在函數聲明之前調用該函數是不會在執行期間報錯,但是函數表達式不同,函數表達式用 var 聲明,也就是說解析器會對其變量提升,並對其賦值為undefined,然后在執行期間,等到執行到該var 變量的時候再將其變量指向一個function函數,所以在函數表達式之前執行該函數是會報錯的。
1 AA(); 2 function AA(){}; 3 4 BB(); 5 var BB = function(){}; 6 7 //AA();不會報錯,因為是以function的變量提升,BB()會報錯,因為是以var的變量提升,到其相當於 BB(); var BB = undefined; BB = function(){};
* function 覆蓋
若定義了兩個同名的函數,則在預解析期間后面一個會覆蓋簽名一個
1 AA(); // 輸出 I am AA_2; 2 function AA(){ 3 console.log('I am AA_1'); 4 }; 5 6 AA(); // 輸出 I am AA_2; 7 function AA(){ 8 console.log('I am AA_2'); 9 }
* 預解析把變量或函數解析到其運行時的環境中
解析器將變量提升並不是將所有的變量都提升到window對象下面,其提升的原則是提升到變量運行的環境中去。
1 aa = "I am aa"; 2 (function(){ 3 console.log(aa); // 輸出 aa 是 undefined 4 var aa = "I am aa in a function"; 5 console.log(aa); //輸出 aa 是 I am aa in a function 6 })(); 7 8 // 這里 aa 被變量提升,但是aa 沒有被變量提升到 window下面,而是被提升到其運行的環境 (function(){ })() 中去,也就是等同於 9 10 // aa = "I am aa"; 11 //(function(){ 12 // var aa; 13 // console.log(aa); // 輸出 aa 是 undefined 14 // aa = "I am aa in a function"; 15 // console.log(aa); //輸出 aa 是 I am aa in a function 16 //})(); 17 18 19 20 // 下面代碼等同於上面,目的是為了若看不懂上面,則可看下面。 21 aa = "I am aa"; 22 function AA(){ 23 console.log(aa); 24 var aa = "I am aa in a function"; 25 console.log(aa); 26 } 27 AA();
* JavaScript“預解析”分段進行
所謂分段進行是按照<script>標簽來分塊進行預解析
1 <script> 2 AA(); // 輸出 AA2; 3 function AA(){ 4 console.log('AA1'); 5 } 6 7 function AA(){ 8 console.log('AA2'); 9 } 10 </script> 11 12 13 <script> 14 function AA(){ 15 console.log('AA3'); 16 } 17 </script> 18 19 //上面例子說明function函數聲明是分塊的,然而至於var變量的提升經過反復驗證是不分塊的( 此處如有不同意見請指教 )。
* var 變量提升以及 function 函數聲明提升
該點是對函數聲明以及函數表達式進一步的說明,其實前面函數聲明和函數表達式在預解析的不同表現,其主要的原因就是 var 和 function 兩者不同的提升。這個問題從解析階段到運行階段來說明。首先,在解析階段 var 后面的 AA 會被提升然后 AA 被定義為undefined,BB 也會被提升,而BB被提升后的內容就是整個 function 里面的內容,其實從瀏覽器的控制台我們可以看出一二。然后,整個解析過程完了就到了運行階段,在運行階段期間,當讀到 AA() 的時候,其實就是將 AA 這個變量指向function(){}這個函數然后調用,而到了 BB() 的時候,就會從之前聲明的函數中去查找該早已經聲明的函數,然后直接調用。
1 var AA = function(){ 2 console.log(' AA_ 1 '); 3 } 4 5 AA(); // 輸出 AA_1 6 7 8 function AA(){ 9 console.log(' AA_2 '); 10 } 11 AA(); //輸出 AA_2 12 13 //這個例子就很好說明了 var 在運行階段動態內建,而 function 在預解析階段靜態建立。
