1. 程式人生 > >JavaScript預編譯原理分析

JavaScript預編譯原理分析

ole ram 語言 screen 三部曲 window pri nts define

今天用了大量時間復習了作用域、預編譯等等知識
看了非常多博文,翻了翻曾經看過的書(好像好多書都沒有講預編譯)
發現當初認為自己學的非常明確,事實上還是存在一些思維誤區
(非常多博文具有誤導性)
今晚就整理了一下淩亂的思路
先整理一下預編譯的知識吧,日後有時間再把作用域具體解說一下


大家要明確。這個預編譯和傳統的編譯是不一樣的(能夠理解js預編譯為特殊的編譯過程)
JavaScript是解釋型語言,
既然是解釋型語言,就是編譯一行。運行一行
傳統的編譯會經歷非常多步驟,分詞、解析、代碼生成什麽的
日後有時間再給大家科普
以下就給大家分享一下我所理解的JS預編譯

JavaScript運行三部曲

腳本運行js引擎都做了什麽呢?

  1. 語法分析
  2. 預編譯
  3. 解釋運行

在運行代碼前。還有兩個步驟
語法分析非常easy。就是引擎檢查你的代碼有沒有什麽低級的語法錯誤
解釋運行顧名思義便是運行代碼了
預編譯簡單理解就是在內存中開辟一些空間,存放一些變量與函數
理解了預編譯對大家理解作用域相同有幫助

JS預編譯什麽時候發生

我當初思維誤區也發生在這裏
預編譯究竟什麽時候發生
希望大家不要讓上面的運行過程讓你產生誤會,
誤以為預編譯只發生在script內代碼塊運行前
這倒並沒有錯
預編譯確確實實在script代碼內運行前發生了
可是它大部分會發生在函數運行前

JS預編譯實例

舉例前。先來思考一下這幾個概念:

  • 變量聲明 var…
  • 函數聲明 function…
<script>
    var a = 1;// 變量聲明
    function b(y){//函數聲明
        var x = 1;
        console.log(‘so easy‘);
    };
    var c = function(){//是變量聲明而不是函數聲明!

//... } b(100); </script> <script> var d = 0; </script>

讓我們看看引擎對這段代碼做了什麽吧

  • 頁面產生便創建了GO全局對象(Global Object)(也就是大家熟悉的window對象)
  • 第一個腳本文件載入
  • 腳本載入完成後。分析語法是否合法
  • 開始預編譯
    • 查找變量聲明,作為GO屬性。值賦予undefined
    • 查找函數聲明。作為GO屬性,值賦予函數體
//偽代碼
GO/window = {
    //頁面載入創建GO同一時候。創建了document、navigator、screen等等屬性。此處省略
    a: undefined,
    c: undefined。
    b: function(y){
        var x = 1;
        console.log(‘so easy‘);
    }
}
  • 解釋運行代碼(直到運行函數b)
//偽代碼
GO/window = {
    //變量隨著運行流得到初始化
    a: 1,
    c: function(){
        //...
    },
    b: function(y){
        var x = 1;
        console.log(‘so easy‘);
    }
}
  • 運行函數b之前。發生預編譯
    • 創建AO活動對象(Active Object)
    • 查找形參和變量聲明,值賦予undefined
    • 實參值賦給形參
    • 查找函數聲明,值賦予函數體
//偽代碼
AO = {
    //創建AO同一時候。創建了arguments等等屬性。此處省略
    y: 100,
    x: undefined
}
  • 解釋運行函數中代碼
  • 第一個腳本文件運行完成。載入第二個腳本文件
  • 第二個腳本文件載入完成後,進行語法分析
  • 語法分析完成。開始預編譯
    • 反復最開始的預編譯步驟……

大家要註意,
預編譯階段發生變量聲明和函數聲明。沒有初始化行為(賦值),匿名函數不參與預編譯
唯獨在解釋運行階段才會進行變量初始化
嗯~最後收一下尾

總結

預編譯(函數運行前)※
1. 創建AO對象(Active Object)
2. 查找函數形參及函數內變量聲明。形參名及變量名作為AO對象的屬性,值為undefined
3. 實參形參相統一,實參值賦給形參
4. 查找函數聲明,函數名作為AO對象的屬性,值為函數引用

預編譯(腳本代碼塊script運行前)
1. 查找全局變量聲明(包含隱式全局變量聲明。省略var聲明),變量名作全局對象的屬性,值為undefined
3. 查找函數聲明。函數名作為全局對象的屬性,值為函數引用


理解了預編譯對理解提升行為,this指向,作用域及性能等問題都有非常大幫助
以後我也會總結這些問題

==主頁傳送門==

JavaScript預編譯原理分析