官术网_书友最值得收藏!

1.1 編譯原理

盡管通常將JavaScript歸類為“動態”或“解釋執行”語言,但事實上它是一門編譯語言。這個事實對你來說可能顯而易見,也可能你聞所未聞,取決于你接觸過多少編程語言,具有多少經驗。但與傳統的編譯語言不同,它不是提前編譯的,編譯結果也不能在分布式系統中進行移植。

盡管如此,JavaScript引擎進行編譯的步驟和傳統的編譯語言非常相似,在某些環節可能比預想的要復雜。

在傳統編譯語言的流程中,程序中的一段源代碼在執行之前會經歷三個步驟,統稱為“編譯”。

· 分詞/詞法分析(Tokenizing/Lexing)

這個過程會將由字符組成的字符串分解成(對編程語言來說)有意義的代碼塊,這些代碼塊被稱為詞法單元(token)。例如,考慮程序var a = 2;。這段程序通常會被分解成為下面這些詞法單元:var、a、=、2 、;。空格是否會被當作詞法單元,取決于空格在這門語言中是否具有意義。

分詞(tokenizing)和詞法分析(Lexing)之間的區別是非常微妙、晦澀的,主要差異在于詞法單元的識別是通過有狀態還是無狀態的方式進行的。簡單來說,如果詞法單元生成器在判斷a是一個獨立的詞法單元還是其他詞法單元的一部分時,調用的是有狀態的解析規則,那么這個過程就被稱為詞法分析

· 解析/語法分析(Parsing)

這個過程是將詞法單元流(數組)轉換成一個由元素逐級嵌套所組成的代表了程序語法結構的樹。這個樹被稱為“抽象語法樹”(Abstract Syntax Tree, AST)。

var a = 2;的抽象語法樹中可能會有一個叫作VariableDeclaration的頂級節點,接下來是一個叫作Identifier(它的值是a)的子節點,以及一個叫作AssignmentExpression的子節點。AssignmentExpression節點有一個叫作NumericLiteral(它的值是2)的子節點。

· 代碼生成

將AST轉換為可執行代碼的過程被稱為代碼生成。這個過程與語言、目標平臺等息息相關。

拋開具體細節,簡單來說就是有某種方法可以將var a = 2;的AST轉化為一組機器指令,用來創建一個叫作a的變量(包括分配內存等),并將一個值儲存在a中。

關于引擎如何管理系統資源超出了我們的討論范圍,因此只需要簡單地了解引擎可以根據需要創建并儲存變量即可。

比起那些編譯過程只有三個步驟的語言的編譯器,JavaScript引擎要復雜得多。例如,在語法分析和代碼生成階段有特定的步驟來對運行性能進行優化,包括對冗余元素進行優化等。

因此在這里只進行宏觀、簡單的介紹,接下來你就會發現我們介紹的這些看起來有點高深的內容與所要討論的事情有什么關聯。

首先,JavaScript引擎不會有大量的(像其他語言編譯器那么多的)時間用來進行優化,因為與其他語言不同,JavaScript的編譯過程不是發生在構建之前的。

對于JavaScript來說,大部分情況下編譯發生在代碼執行前的幾微秒(甚至更短!)的時間內。在我們所要討論的作用域背后,JavaScript引擎用盡了各種辦法(比如JIT,可以延遲編譯甚至實施重編譯)來保證性能最佳。

簡單地說,任何JavaScript代碼片段在執行前都要進行編譯(通常就在執行前)。因此,JavaScript編譯器首先會對var a = 2;這段程序進行編譯,然后做好執行它的準備,并且通常馬上就會執行它。

主站蜘蛛池模板: 融水| 孟津县| 呼图壁县| 土默特右旗| 固原市| 朝阳县| 固阳县| 靖边县| 阿瓦提县| 搜索| 舟曲县| 平泉县| 丰城市| 大埔区| 迁西县| 沾化县| 郎溪县| 广汉市| 墨江| 东方市| 乐东| 比如县| 柏乡县| 百色市| 沙河市| 寻甸| 尼玛县| 汝南县| 潍坊市| 太仓市| 天祝| 金寨县| 新绛县| 晋宁县| 巨野县| 游戏| 高邮市| 洛浦县| 余江县| 宣化县| 阿克陶县|