JS代碼運行過程簡述(一)

JS 是動態語言,任何一段代碼在執行以前都須要編譯,它跟傳統的語言不一樣,它不是提早編譯的,編譯結果也不能在分佈式系統中進行移植。
可是JS引擎進行編譯的步驟和傳統的編譯語言很是類似,在某些環節可能比預想的要複雜。編程

傳統的編譯

  • 分詞/詞法分析(Tokenizing/Lexing)
    這個過程會將由字符串組成的字符串分解成(對編程語言來講)有意義的代碼塊,這些代碼塊被稱爲詞法單元(token)數組

e.g. var a = 2;
一般會被解析成var 、a、=、二、;
空格是否被當作此法單元,取決於空格在這門語言中是否具備意義編程語言

  • 解析/語法分析(Parsing)
    這個過程是將詞法單元流(數組)轉換成一個由元素逐級嵌套所組成的表明了程序語法結構的樹(抽象語法樹,Abstract Syntax Tree, AST)分佈式

var a = 2;函數

VariableDeclaration
|
|------ a
|------AssignmentExpression
    |-----2
  • 代碼生成
    將AST轉換成可執行代碼的過程。this

var a = 2;
經過特定方法將var = 2;的AST轉化爲一組機器指令,用來建立一個叫做a的變量(包括內存分配等),並將一個值存儲到a中。code

JS 編譯

JS 的編譯步驟和傳統仍是很是類似的,只是某些環節比較複雜,這裏我詳細說一下「預編譯」,其餘三個步驟同傳統的編譯對象

  • 分詞/詞法分析(Tokenizing/Lexing)token

  • 解析/語法分析(Parsing)內存

  • 預編譯
    首先先看一個例子:

function a(b) {    
      alert(b); 
    function b() {            
        alert(b);       
    }        
    b();    
}    
a(1);

答案先不說, 如今看具體的預編譯過程:

  1. 預編譯--全局
    1). 建立Global Object對象(GO)

2). 查找變量聲明

-> 若是GO上尚未該屬性,則添加該屬性,值爲undefined  
-> 若是GO上已經有該屬性,則不作任何處理

3). 查找函數聲明(eg. function foo () {})

-> 若是GO上尚未foo屬性,則把函數賦值給foo屬性  
 -> 若是GO上已經存在foo屬性,則直接覆蓋
  1. 預編譯--函數
    1). 函數運行前的一瞬間,生成Activation Object(活動對象),簡稱AO

2). 分析參數

-> 把聲明的參數造成AO的屬性,值全爲undefined  
 -> 接收實參,造成AO相應屬性的值

3). 分析變量聲明

-> 若是AO上尚未該屬性,則添加該屬性,值爲undefined  
 -> 若是AO上已經有該屬性,則不作任何處理

4). 分析函數聲明(eg. function foo () {})

-> 若是AO上尚未foo屬性,則把函數賦值給foo屬性  
 -> 若是AO上已經存在foo屬性,則直接覆蓋
  • 代碼生成
    JS執行過程簡單的介紹完了,Do you get it?, 下面看以前例子分析:

function a(b) {    
      alert(b); 
    function b() {            
        alert(b);       
    }        
    b();    
}    
a(1);


// 分析以下
/*
 * 1. 建立GO對象(包含JS全局對象的內置對象Math、String、Date、etc)
 * 2. 查找變量聲明,沒有
 * 3. 查找函數聲明,定義函數a, GO = {a: function () {}}
 * 4. 執行a(1)
 * // 如下爲函數a運行前的編譯
 * 5. 建立活動對象AO  AO={this, arguments}
 * 6. 分析形參 AO = {this, arguments, b: undefined}
 * 7. 接收實參 AO = {this, arguments, b: 1}
 * 8. 分析變量聲明 AO = {this, arguments, b: 1}
 * 9. 分析函數聲明 
     AO = {
         this
         argunments,
         b: function () {}
     }
 
 * // 執行
 * alert(b)  // function () { ... }
 * b()   // function () { ... }
 */

從以上分析很清晰就可以知道彈出兩個function,是否是很簡單啊。其實在執行b(),還有函數b也要編譯哦,編譯步驟同函數a,這裏就不作分析了。
習題:

function a(b) {    
      alert(b); 
    b = function() {            
        alert(b);       
    }        
    b();    
}    
a(1);

本身試着分析一下,結果是1和function,你作對了麼?難點:b = function () {}這個是一個賦值語句

相關文章
相關標籤/搜索