計算機不能直接理解高級語言,只能直接理解機器語言,因此必需要把高級語言翻譯成機器語言,計算機才能執行高級語言編寫的程序。根據語言的執行流程,能夠把語言分紅編譯型語言和解釋型語言。javascript
編譯型語言:程序在執行以前須要一個專門的編譯過程,把程序編譯成 爲機器語言的文件,運行時不須要從新翻譯,直接使用編譯的結果就好了。程序執行效率高,依賴編譯器,跨平臺性差些。如C、C++、go等.java
解釋型語言: 程序不須要編譯,程序在運行時才翻譯成機器語言(因此執行前須要環境中安裝瞭解釋器),每執行一次都要翻譯一次。所以效率比較低。效率比較低,依賴解釋器,跨平臺性好。數據庫
編譯型與解釋型,二者各有利弊, 不能一律而論。前者因爲程序執行速度快,同等條件下對系統要求較低,所以像開發操做系統、大型應用程序、數據庫系統等時都採用它,像C/C++、Pascal/Object Pascal(Delphi)等都是編譯語言,而一些網頁腳本、服務器腳本及輔助開發接口這樣的對速度要求不高、對不一樣系統平臺間的兼容性有必定要求的程序則一般使用解釋性語言,如JavaScript、VBScript、Perl、Python、Ruby、MATLAB 等等。
咱們都知道 JavaScript 存在變量提高,在函數做用域內的任何變量的聲明都會被提高到頂部而且值爲 undefined。
因此JS引擎好像對同一個腳本執行了兩次,第一次完成全部聲明,而後第二次才執行代碼?仍是先編譯整個代碼而後運行它?這兩種都不對。編程
其實變量聲明不過只執行上下文的小把戲。在執行任何語句以前,解釋器就要從建立執行上下文後已經存在的做用域中找到變量的值。瀏覽器
抽象語法樹(Abstract Syntax Tree,AST),或簡稱語法樹(Syntax tree),是源代碼語法結構的一種抽象表示。它以樹狀的形式表現編程語言的語法結構,樹上的每一個節點都表示源代碼中的一種結構。之因此說語法是「抽象」的,是由於這裏的語法並不會表示出真實語法中出現的每一個細節。好比,嵌套括號被隱含在樹的結構中,並無以節點的形式呈現;而相似於 if-condition-then 這樣的條件跳轉語句,可使用帶有兩個分支的節點來表示。緩存
字節碼(Byte-code):是一種包含執行程序、由一序列 op 代碼/數據對組成的二進制文件。字節碼是一種中間碼,它比機器碼更抽象。服務器
機器碼 (Machine-code):計算機直接使用的程序語言,其語句就是機器指令碼,機器指令碼是用於指揮計算機應作的操做和操做數地址的一組二進制數。數據結構
生成AST的步驟能夠拆分紅如下兩個小步驟:架構
經過 javascript-ast 網站,能夠大概瞭解 代碼生成的 Tokens 以及 AST大體的樣子。
例如let a = 2;
,一般會被分解爲下面這些詞法單元 let
、a
、=
、2
、;
空格是否會被當作詞法單元取決於空格在這門語言中是否會具備意義。編程語言
let a = 2; console.log(a);
咱們能夠看到生成的AST結構以下:
高級語言是開發者能夠理解的語言,編譯器和解釋器理解不了。因此不管你使用的是解釋型語言仍是編譯型語言,在編譯過程當中,它們都會生成一個 AST。當生成 AST以後,編譯器/解析器後續的工做都要依靠 AST而不是源碼。
AST是一個很是重要數據結構,好比Babel的工做原理就是: ES6 的代碼解析成 AST -> 將 ES6 的 AST 轉換成 ES5 的AST -> 將 ES5的 AST 轉成 ES5的代碼。Babel的相關文章推薦 深刻淺出 Babel 上篇:架構和原理 + 實戰;咱們使用的 Eslint(檢查JavaScript編寫規範的插件) 的檢測流程也是先將源碼轉換成 AST, 而後利用 AST 來檢查代碼規範的問題
JavaScript引擎經過解釋器來將 AST 轉換成字節碼,字節碼是沒法直接執行的,須要將其轉爲機器碼才能直接執行。V8早期的時候,是直接將AST轉成機器碼的,後來由於 V8 須要消耗大量的內存來存放轉換後的機器碼,致使嚴重的內存佔用問題。爲了解決這個問題,引入 了字節碼。字節碼是比機器碼輕量得多的代碼。
字節碼是介於 AST 和機器碼之間的一種代碼。可是與特定類型的機器碼無關,字節碼須要經過解釋器將其轉換成機器碼後才能執行。
生成字節碼以後,就到了解釋和執行字節碼階段了,
解釋器會逐條執行字節碼,(解釋器除了負責生成字節碼,還會負責解釋執行機器碼) 若是發現一段代碼重複執行屢次,就會它記爲熱點代碼(HotSpot),V8會將這段熱點代碼提交給優化編輯器,優化編輯器會在後臺將字節碼編譯爲二進制代碼,而後在對編譯後的二進制代碼執行優化操做,並保存下來。保存下來的機器碼的做用和緩存很相似,當解釋器再次遇到相同的內容時,就能夠直接執行保存下來的機器碼。
這樣代碼執行得越久,執行效率就會越快,由於會有愈來愈多的字節碼被標記爲 熱點代碼,遇到他們就能夠直接執行,而不用轉成機器碼。
JavaScript是一種很是靈活的動態語言,對象的結構和屬性在運行時任意被改變,而通過優化後的代碼只能針對某種固定結構。一旦在執行過程當中,對象的結構被動態修改了,那麼優化後的代碼會變成無效的代碼,這時候優化編輯器就須要執行反優化操做,通過反優化的代碼下次執行時就會回退到解釋器解釋執行。
字節碼的執行是須要配合編譯器和解釋器的(這種技術稱爲即時編譯 JIT)因此以前說 JS是一種解釋型語言並不許確。
整個過程以下面流程圖所示: