原文地址,對於常見編譯型語言(例如:Java)來講,編譯步驟分爲:詞法分析->語法分析->語義檢查->代碼優化和字節碼生成。javascript
對於解釋型語言(例如 JavaScript)來講,經過詞法分析 -> 語法分析 -> 語法樹,就能夠開始解釋執行了。html
具體過程是這樣的: java
1.詞法分析是將字符流(char stream)轉換爲記號流(token stream)git
NAME "AST" EQUALS NAME "is Tree" SEMICOLON
2.語法分析成 AST (Abstract Syntax Tree),你能夠在這裏試試 http://esprima.org/ github
3.預編譯,當JavaScript引擎解析腳本時,它會在預編譯期對全部聲明的變量和函數進行處理!而且是先預聲明變量,再預約義函數!ide
4.解釋執行,在執行過程當中,JavaScript 引擎是嚴格按着做用域機制(scope)來執行的,而且 JavaScript 的變量和函數做用域是在定義時決定的,而不是執行時決定的。JavaScript 中的變量做用域在函數體內有效,無塊做用域;函數
function func(){ for(var i = 0; i < array.length; i++){ //do something here. } //此時 i 仍然有值,及 i == array.length console.log(i); // 但在 java 語言中,則無效 }
JavaScript 引擎經過做用域鏈(scope chain)把多個嵌套的做用域串連在一塊兒,並藉助這個鏈條幫助 JavaScript 解釋器檢索變量的值。這個做用域鏈至關於一個索引表,並經過編號來存儲它們的嵌套關係。當 JavaScript 解釋器檢索變量的值,會按着這個索引編號進行快速查找,直到找到全局對象(global object)爲止,若是沒有找到值,則傳遞一個特殊的 undefined 值。優化
var scope = "global"; scopeTest(); function scopeTest(){ console.log(scope); var scope = "local"; console.log(scope); } 打印結果:undefined,local;
咱們常說的 V8 是 Google 發佈的開源 JavaScript 引擎,採用 C++ 編寫。SpiderMonkey(Mozilla,基於 C)、Rhino(Mozilla,基於 Java),而 Nodejs 依賴於 V8 引擎開發,接下來的內容是 JavaScript 在 V8 引擎中的運行狀態,而相似的 JavaScript 現代引擎對於這些實現大同小異。spa
在本文的開頭提到了編譯型語言,解釋型語言。JavaScript 是解釋型語言且弱類型
,在生成 AST 以後,就開始一邊解釋,一邊執行,可是有個弊端,當某段代碼被屢次執行時,它就有了可優化的空間(好比類型判斷優化),而不用一次次的去重複以前的解釋執行。
編譯型語言如 JAVA,能夠在執行前就進行優化編譯,可是這會耗費大量的時間,顯然不適用於 Web 交互。code
因而就有了,JIT(Just-in-time),JIT 是兩種模式的混合。
它是如何工做的呢:
1.在 JavaScript 引擎中增長一個監視器(也叫分析器)。監視器監控着代碼的運行狀況,記錄代碼一共運行了多少次、如何運行的等信息,若是同一行代碼運行了幾回,這個代碼段就被標記成了 「warm」,若是運行了不少次,則被標記成 「hot」。
2.(基線編譯器)若是一段代碼變成了 「warm」,那麼 JIT 就把它送到基線編譯器去編譯,而且把編譯結果存儲起來。好比,監視器監視到了,某行、某個變量執行一樣的代碼、使用了一樣的變量類型,那麼就會把編譯後的版本,替換這一行代碼的執行,而且存儲。
3.(優化編譯器)若是一個代碼段變得 「hot」,監視器會把它發送到優化編譯器中。生成一個更快速和高效的代碼版本出來,而且存儲。例如:循環加一個對象屬性時,假設它是 INT 類型,優先作 INT 類型的判斷
4.(去優化)但是對於 JavaScript 歷來就沒有肯定這麼一說,前 99 個對象屬性保持着 INT 類型,可能第 100 個就沒有這個屬性了,那麼這時候 JIT 會認爲作了一個錯誤的假設,而且把優化代碼丟掉,執行過程將會回到解釋器或者基線編譯器,這一過程叫作去優化。
「hot」 代碼
優化前
優化後
明白一些基本原理能拓展出更多的東西,好比:
1.var a = 10; var b = 20; ==> var a=10, b=20; 這些改代碼的好處是什麼,如何從原理解釋?
2.JavaScript 的函數和變量是在何時聲明的,函數聲明和函數表達式的區別?
3.如何經過編譯器的優化原理,如何提升 JavaScript 的執行效率?
做者:肖沐宸,github。