六角學院 JS 核心筆記 (一)【執行環境與作用域】- JavaScript 是如何運行的

程式的運作

我們一般寫出來的程式碼又稱做原始碼,屬於高階式 (類人類) 語言,這種語言電腦是看不懂的,電腦只懂 0 和 1,因此需要經過中間用來翻譯的程式,將原始碼翻譯成機器碼。翻譯程式可以依照不同類型稱為編譯器直譯器

依照不同的翻譯類型,有以下三種分類,JavaScript 屬於直譯式語言

編譯式語言:C、C++

  • 運作:原始碼 → 預先編譯(除錯) → 機器碼 → 電腦執行
  • 說明:執行期間,原始碼已經全部被編譯完,因此運行速度 (runtime) 較快,效率佳。錯誤會在執行前出現。

直譯式語言:JavaScript、Python

  • 運作:原始碼 → 直譯器 → 機器碼 → 電腦執行
  • 說明:執行期,動態將程式碼逐句直譯(interpret)為機器碼。錯誤會在環境中產生。

即時編譯技術:Java、LLVM、C#

  • 說明:混合了編譯語言與直譯語言的優點,它像編譯語言一樣,先把程式原始碼編譯成位元組碼。到執行期時,再將位元組碼直譯,之後執行。
  • 關於即時編譯技術可以參考我之前寫的筆記 C# 程式的執行方法

直譯器轉換過程

完整的步驟是:
解構成 token → 抽象語法樹 AST (Abstract Syntax Tree) → 機器碼

直譯器在一句一句閱讀程式碼時,會將其解構成一個一個語法單元 (token,也就是 word 或 phrase),這個過程稱作 tokenization。再將每個 token 和其左右兩邊的 token 相對照,依照 token 之間的關係或語法產生相對應的語法結構樹。最後依照結構樹轉換成機器碼

課程中提供一個解構網站 Esprima 讓大家了解何謂 token 和 AST。

舉例

以下的例子,一個是宣告並且賦予初始值,一個是賦予變數值。但是 type 卻是完全不一樣的:VariableDeclaration、ExpressionStatement。

語法單元 Tokens

  • Keyword:關鍵字
  • Identifier:識別符
  • Punctuator:標點符號 (數學、結束)
  • String / Numeric:型別
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
Tokens  (var answer = 6 * 7;)

[
{
"type": "Keyword",
"value": "var"
},
{
"type": "Identifier",
"value": "answer"
},
{
"type": "Punctuator",
"value": "="
},
{
"type": "Numeric",
"value": "6"
},
{
"type": "Punctuator",
"value": "*"
},
{
"type": "Numeric",
"value": "7"
},
{
"type": "Punctuator",
"value": ";"
}
]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
Tokens  (answer = "2" * 7;)

[
{
"type": "Identifier",
"value": "answer"
},
{
"type": "Punctuator",
"value": "="
},
{
"type": "String",
"value": "\"2\""
},
{
"type": "Punctuator",
"value": "*"
},
{
"type": "Numeric",
"value": "7"
},
{
"type": "Punctuator",
"value": ";"
}
]

語法 Syntax

var answer = 6 * 7; 的語法解說:

  • VariableDeclaration:變數宣告
    • declarations:宣告
      • id - Identifier:識別符
      • init:初始化,有運算符號 (operator *) ,和運算符號的左邊 (6) 和右邊 (7)。
    • kind:宣告種類 (var)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
Syntax  (var answer = 6 * 7;)

{
"type": "Program",
"body": [
{
"type": "VariableDeclaration",
"declarations": [
{
"type": "VariableDeclarator",
"id": {
"type": "Identifier",
"name": "answer"
},
"init": {
"type": "BinaryExpression",
"operator": "*",
"left": {
"type": "Literal",
"value": 6,
"raw": "6"
},
"right": {
"type": "Literal",
"value": 7,
"raw": "7"
}
}
}
],
"kind": "var"
}
],
"sourceType": "script"

answer = "2" * 7; 的語法解說:

  • ExpressionStatement:表達式敘述
    • expression:表達式
      • operator:運算符號 =
      • left:左邊,是 Identifier
      • right:右邊,另一個表達式,一樣有 operator、left 和 right
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
Syntax  (answer = "2" * 7;)

{
"type": "Program",
"body": [
{
"type": "ExpressionStatement",
"expression": {
"type": "AssignmentExpression",
"operator": "=",
"left": {
"type": "Identifier",
"name": "answer"
},
"right": {
"type": "BinaryExpression",
"operator": "*",
"left": {
"type": "Literal",
"value": "2",
"raw": "\"2\""
},
"right": {
"type": "Literal",
"value": 7,
"raw": "7"
}
}
}
}
],
"sourceType": "script"
}

參考資料:
六角學院:JavaScript 核心篇 - 邁向達人之路