在瞭解 JavaScript 是如何運行前,我們要先瞭解在 script 中所寫的原始碼電腦是無法直接解讀的,這些語法都要轉換成電腦看得懂的代碼才有辦法運行,而語法的轉換則分成兩種,編譯式語言與直譯式語言:
編譯式語言(Compiled language)
在我們寫好原始碼時,會先透過編譯器(compiler)預先編譯完成並生成代碼,電腦才會解讀並執行,這樣的語言有下列幾項特色:
- 編譯時即可除錯。
- 預先定義的型別。
- 型別檢查 (type check)。
- 擁有高效能的執行速度等特性。
- 可獨立執行。
直譯式語言(Interpreted language)
不同於編譯式語言,直譯式語言在執行時會一行一行的動態將程式碼直譯為代碼,並執行,因此會有下列的特色:
- 錯誤直接反映在環境上。
- 不用預先定義的型別。
- 動態生成。
- 程式彈性。
- 速度會比編譯式語言要慢一些。
- 無法獨立運行,可用的功能由執行環境所提供。
JavaScript 直譯器的轉換過程
在直譯器的轉換過程中,首先會將語法單元化(Tokenizing),然後透過抽象結構樹(Abstract Syntax Tree )將原始碼的結構定義出來,最後生成代碼運行。
接下來我們利用 https://esprima.org/demo/parse.html 來解析轉換得過程。
語法單元化
從下圖我們可以看到,我們所寫語法的每個單詞都會被單元化並解析為各種 type,例如 var 他並不會知道他有宣告變數的功能,而是辨識它為關鍵字,= 也不會知道它有賦予值的功能,而辨識它是一個標點符號。
抽象結構樹
抽象結構樹會針對我們原本所要做的行為(這邊我們主要行為是宣告一個變數)來帶入不同的方法,在圖的下方有個 kind ,可以知道我們用來定義變數的方法是 var,若我們改成 ES6 中的 let 來宣告變數,則 kind 會變成 let。
另外,我們知道當沒使用 var 宣告變數,而是直接對變數賦予值時會變成全域變數,從抽象結構樹也可以看到兩種方式的差別,一種是使用 VariableDeclarator 變數宣告的方法,直接賦予值是使用 AssignmentExpression 指派的方法。