---
# System prepended metadata

title: 我所不知道的 JavaScript (下)：應用篇
tags: [API, Event Driven, Cross Platform, Runtime, ABI, Automata, AOT, Web Technology, Optimization, App, C, JavaScript, Compiler, C++, Linux, System Design, TurboFan, JavaScript Engine, JIT, JVM, V8, Software, UNIX, Operating System, Python, Compiler Design, Java, Kernel, Rust, Security]

---

# 我所不知道的 JavaScript (下)：應用篇
###### tags: `JavaScript` `JavaScript Engine` `Java` `JVM` `Python` `C` `C++` `Rust` `Runtime` `System Design` `App` `API` `ABI` `Web Technology` `Event Driven` `Cross Platform` `AOT` `JIT` `Compiler` `V8` `TurboFan` `Compiler Design` `Optimization` `Security` `Operating System` `Linux` `Kernel` `Software` `Automata` `UNIX`

記錄多個 JavaScript 語言背後設計哲學、JavaScript 系統環境架構、程式行為與最佳化、ECMAScript 擴充、各技術規範標準和相依平台 API 實作之討論。

:::info
:arrow_right: 上篇：[我所不知道的 JavaScript (上)：理論篇 - shibarashinu](https://hackmd.io/@shibarashinu/BkAHFociR)。
:::

![](https://hackmd.io/_uploads/Bk2Bmbsfyl.png)
> ~~標題剽竊~~ 標題參考自 [「你所不知道的 C 語言」系列講座 - jserv](https://hackmd.io/@sysprog/c-programming)。

## JavaScript Standard

### Execution Contexts
任何有關此次 function call 的參考要素都記載於此，以此塑造「執行環境」以提供 ==runtime 函式程序== 必要協助，通常與 call stack 上的 stack frame 綁定。例如: Scope、Declaration、函式相關資料。

> 銜接靜態 program 和動態 process 之間缺乏的要素。

:::info
**Execution Context vs. Call Stack**

- **Memory Stack:**
    搭配 Register 作為 Von Neumann 結構的記憶單元。
    - **Execution Context:** 應用狀態機之動態記憶 ==系統環境== 資料 (向開發者隱藏)。
    - **Call Stack:** 應用狀態機之動態記憶 ==使用者程式== 資料 (向使用者隱藏)。
    
> 由面向開發者的「程式語言」包裝，再由面向實際處理的「執行系統」 (e.g., Operating Systems, Runtime Systems) 實作，一同合作實現計算機功能，完成任務。

雖在 runtime 機器中，execution context 常與 stack frame 一塊實作，但各為不同目的所存在，應確實區分兩者用途。

更多:
- [JavaScript Execution Context and Lexical Environment Explained. - Vince Llauderes - HackerNoon](https://hackernoon.com/javascript-execution-context-and-lexical-environment-explained-528351703922)
    ![image](https://hackmd.io/_uploads/SJBv5lof1e.png =400x)
:::

:arrow_right: 詳見: [Exploring the JavaScript Engine - shibarashinu](https://hackmd.io/@shibarashinu/r1XdprVCj)

### Scope
當前函數執行的 scope 環境，即目前程式 execution context 的作用域、權限、程序下所能觸及的變數資源的「可視範圍」，如: 可否定位目標變數以做數值 bindings。

> 掌握程式語言的變數 scope 行為對程式開發、操控和執行效能有重大影響。

[Scope - MDN Web Docs](https://developer.mozilla.org/en-US/docs/Glossary/Scope)

:::danger
**注意: JavaScript 作為一動態語言，必須小心與其他語言在 Lexical Scope、Variable Declaration 和 Runtime 等處理手法上的不同**

如 *hoisting*、*execution context* 與 *this*、*first-class function*、*closure* 概念等。

例如:
- C++:
    - **Scope:** 每一個 block 都視為是新的局部 scope 作用域。
        > JavaScript 在 ECMAScript 2015 引入 `let` / `const` 後才有此種 block scope 概念，不然原 `var` 只論及 function scope 作用域參考！
    - **Closure (Lambda Function's Capture):** 可選擇 Pass by Value 或 Reference、選擇性傳遞、能否修改 (mutable)，C++ 中的匿名函數閉包參數傳遞比起 JavaScript 和 Python 有更多可選控制。
        ```cpp=
        [&] () {}
        ```
- Python:
    - **Scope:** 沒有 block scope 只有 function scope 作用域！所以在同一 function 內的所有變數都是函式中可被參照到的對象。
        > 行為上和在 JavaScript 中純使用 `var` 雷同。
        ```python=
        def func():
            for i in range(10):
                k = i
            print(i, k)  // 9, 9
        
        func()
        ```
    - **Closure:** 由於 Python 沒有宣告變數用的 keyword，所以只能靠在 stack 中從下往上盲找最近的「變數賦值」來判斷是否為 closure 作用域，但是也可使用 `nonlocal` / `global` 來指定要往哪個 scope 找。

    參考:
    - [【python】详解变量作用域，局部闭包还是全局？ - 码农高天](https://www.youtube.com/watch?v=k9D_HYaW_68)
:::

:::danger
**JavaScript 函數 Closure 與其他具 Block Scope 程式語言之比較**

在低階程式語言如 C/C++ 中，變數一旦離開 block scope 即無法存取 (在 stack 上已被 pop 掉)，若變數指向 heap 上則必須改以其指標形式操作 (e.g., 在 block 中用 `void*`，block 外必須用 `void**`，因為此時 `void*` 已失效)，若硬是要存取已失效的變數則會導致未預期行為 (理論上編譯器會阻止)。

但 JavaScript (和 Python) 具高階語言特色的「closure」機制，規定目標函數可存取的變數 scope 為「函數定義當下的執行 context」的變數 scope 作用域 — 即使原函數以離開該函數環境，==在 call stack 上本應該被釋放的資源，因為有內部函數的 closure 在原函數外有參照，使 JavaScript 引擎在一開始就會分析這些可被 closure 捕獲的變數，並預先將他們配置在 heap 上而非 stack==。

有了此額外的目標函式 context 的 closure 指向這些區域變數，使其在原函式生命週期結束時免於被釋放 (`refernece_count > 0`)。

更多:
- 參考 CPython 上對 Closure 機制的實作: [【python】闭包的实现机制。嵌套函数怎么共享变量的？ - 码农高天](https://www.youtube.com/watch?v=Flce9y5Qn38)
:::

#### Closure
*一個函數執行時能存取到的變數 scope 環境。*

考慮以下程式碼:
```javascript=
function Print() {
    let inner_value = 0;

    function inner_print() {
        console.log(`Hello ${inner_value++}`);
    }
    return inner_print;
}

// inner_print & inner_value still can be accessed!
const print = Print();
print();  // Hello 0
print();  // Hello 1
print();  // Hello 2
```

<!-- :warning: -->

:::warning
在 Symbol.iterator (見下章節) 中將一般函式作為「**自訂可迭代 (user-defined iterables)** 」方法時便可看到 Closure 的實際應用場景。
:::

:::warning
**技巧: 利用 Closure 在 Promise 的 Callback 中參照異步操作前的變數**

透過 closure 實現在具「同步處理」和「異步 Promise」的函式中可存取同一變數 — 我可以先宣告未來「異步 Promise」會執行的 callback 函式變數，再在 Main Thread 中慢慢 ++define 該 callback 程序++，最終再由「異步 Promise」觸發 ++fulfill 該 callback 程序++。

應用:
- RPC 模組開發。
    ```javascript=
    exports.send = function ({ action, data, need_resolve = true }) {
        const sendID = client.get_sendID();
        client.send({ sendID, action, data });

        if (need_resolve)
            // Register a promise function & return the RPC result.
            return new Promise(res => {
                _resolve[sendID] = function (data) {
                    delete _resolve[sendID];
                    res(data);  // Here the event actually returns Promise's result.
                };
            });
    };
    ```
:::

相關資源:
- [Closures - MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures)
- [[Book] You Don't Know JS Yet: Scope & Closures - 2nd Edition - getify](https://github.com/getify/You-Dont-Know-JS/blob/2nd-ed/scope-closures/README.md)

### Literals
*"Data that ++literally++ provide in the binaries (JS script in this context)".*

為存在記憶體中「固定大小且有特別意義、編排」的資料結構，可被有意義的 *Expression* 所操作，如: 賦予變數特定的數值。

#### JavaScript 基礎資料型別
:::info
**JavaScript 各型態分類 (Type Categories):**

- **Values:** 程式 semantic 分析使用。
    > ![image](https://hackmd.io/_uploads/HJ10clsfJg.png =500x)
    > 
    > (Source: [Data Class Reference - V8 Docs](https://v8docs.nodesource.com/node-0.8/d1/d83/classv8_1_1_data.html))
    - **Primitives:** *Boolean*, *Number*, *BigInt*, *String*, *undefined*, *null*, *Symbol*。
    - **Non-Primitives:** *Object*, *Array*, *Function*。

- **Literals:** 實際運行程式所使用 value 之型態。
    - *Array*, *Boolean*, *Numeric (int, float)*, *Object*, *RegExp*, *String*。

其中 semantic values 部份可用 built-in 運算子 `typeof` 查詢:
```javascript
console.log(typeof /regex/);  // "object"
```

或由 constructor 鍵值判斷:
```javascript
const arr = [];

console.log(arr.constructor === Array);  // true
console.log("".constructor === String);  // true

```

[Grammar and types - MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Grammar_and_types)
:::

:arrow_right: 延伸在 C++ 相關 semantic 資料型態分類討論: [[C++] Your Rvalue Isn't Meant to Be the Rvalue - shibarashinu](https://hackmd.io/@shibarashinu/By3XL37d0)

#### 程式中的 Literal 關係

literal 概念上屬於 `Rvalue` 型態: *literal* 作為「受質」，可與 *identifier*「繫結」始可被變數、參數等「受體」容器所存取，*literal* 所乘載在記憶體上的實體內容則為的 *value*。

:::warning
**程式編譯角度:**

在編譯過程中，(1) 識別 *identifier (variable)* 和 *literal (value)* 等等 tokens；(2) 檢查程式文句語法；(3) 再將他們繫結成一句有意義的完整行為描述的步驟，分別在 lexical、syntax 和 semantic 分析時產生。
:::

:::warning
**程式執行角度:**

在可執行程式中，「*定義 literal*」等價於「*使用該資料結構的 initializer*」。
:::

:::info
**Identifiers vs. Variables**

*identifier* 用作代表程式碼某項元件的「名字」，以識別、操作特定元件。

*variable* 則是可儲存資料的「元件」，廣義上來說，可被編譯器轉化映射成以下任何 ==可被定址、可做讀寫資料操作的區塊==:
- SRAM: register (間接影響 L1/L2/L3 cache)、interrupt line、controller 控制、buffer 等。
- DRAM: stack、heap、page 等。
- EEPROM: BIOS、UEFI、firmware config 等。
- Storage: frame、block、sector 等。
- I/O Device: driver、socket、buffer 等。
- Circuit: MCU、FPGA 等。
- 其他: 打孔紙、燈泡、真空管等。

即是為 variable 的載體 (GLvalue in C++)。端看使用場景、計算設備架構、描述語言 (IDL、DSL、Devicetree、HDL 等) 和編譯器如何實現一支可利用「variable 來操作元件」做特定用途的程式。

> 好似「Linux VFS」的核心精神。

更多:
- [Binding - MDN Web Docs](https://developer.mozilla.org/en-US/docs/Glossary/Binding)
:::

:::info
**Literals vs. Values**

*value* 為一串無意義的「數值」(i.e. 訊號、映像、數據)，不一定是由程式碼直接提供，只要可被 *variable* 儲存的任何 pattern 都可視作 *value*。

> 在 JavaScript 中，所有 *value* 以 *Primitives* 或 *Non-Primitives* (Objects) 形式體現。

*literal* 為儲存在記憶媒介中有意義的「資料結構」，載明在程式碼並在執行時由 runtime 載入。

> 可視作 *literal* 包裹 *value*，賦予其特別意義 (e.g., 特定型態、編解碼方法、用法) 成為有用的資料型態，始可被程式所用。

Refs:
- [Difference between values and literals - StackOverflow](https://stackoverflow.com/questions/18970938/difference-between-values-and-literals)
:::

#### 與其他程式語言之 Literals 比較

在 compiled language 如 C，literals 會被存於與目標檔案系統相依，且與作業系統載入相關的 ABI 相容之++檔案++ / ++程序++區塊中 (i.e., 存放於 ELF 標準中的 *.rodata*, etc. 的 ++section++ / ++segment++)；而如 JavaScript 的動態語言則是將 literal 存於 *code text* 中，再動態載入至記憶體 (call stack 或 heap)。

#### Array Literals
:::danger
**JavaScript 中 Array Literals 的特例定義**

JavaScript 允許在陣列中定義空項目 *(empty item)*:
```javascript
const arr = [, "B"];  // [<1 empty item>, "B"]
```

此空項目在陣列定義中既不是 `undefined` 亦不是 `null` ---- 不屬於任何 *Primitives*。在 traverse 時會跳過，在 index 存取時會回傳 `undefined`。
:::

#### String Literals
:::info
**語法糖: Template Tag Function**

*Template Literal* 指的是 \``...`\` 這種 String Literals 表示形式，*Tag Function* 是利用這種語法產生的特別函數表示，一種處理 "String as Input" 的函數更簡潔的寫法。

例:
```javascript=
const processArg = (arg) => {
    if (Array.isArray(arg))
        return arg.map((item) => `\n  arr: ${item}`);
    else if (arg.toString === Object.prototype.toString)
        return JSON.stringify(arg);
    return arg;
};

/*
 * segments: string that lies between the arguments.
 * For example, `seg[0]...${arg[0]}...seg[1]...${arg[1]}`
 */
const print = (segments, ...args) => {
    let result = segments[0];

    segments.slice(1).forEach((seg, index) => {
        const arg = processArg(args[index]);
        result += arg + seg;
    });
    
    console.log(result);
};

const arr = [1, 2, 3];

const obj = { a: 0, b: 1 };

print`Template Tag Function:
My Arr: ${arr}
My Obj: ${obj}
`;

/*
 * "Template Tag Function:
 * My Arr: 
 *   arr: 1,
 *   arr: 2,
 *   arr: 3
 * My Obj: { "a": 0, "b": 1 }
 */
```
:::

### Symbol
*Primitive Data Type* (ECMAScript 2015)

使用 `Symbol` 來保證 property 唯一性使用，且不會被覆蓋掉。可用於 Object 中 properties 衝突的情況。其用意為提供物件內部方法，由 runtime 機制保護使外部無法存取的一種「封裝」形式。

[Symbol - MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol)

```javascript=
let s = Symbol("name: s");

let obj = {
    [s]: s.toString()
};

console.log(obj[s]);  // "Symbol(name: s)"
```

:::info
**Well-Known Symbol**

以 Symbol 來客製化修改 JavaScript 原生語言行為，例如: 定義 Object 的 constructor 中的 `Symbol.hasInstance` 屬性，JavaScript 引擎會在執行時動態使 `instanceof` 語法轉而調用此自定義的函式。

```javascript=
class MyArray {
  static [Symbol.hasInstance](instance) {
    return Array.isArray(instance) ? "YES" : "NO";
  }
}

const arr = [1, 2, 3];
console.log(arr instanceof MyArray);  // YES
```

<!-- :warning: -->
:::

### Symbol.iterator / .asyncIterator
在物件的 prototype 中定義的保留靜態變數 `Symbol.iterator`，用以識別、指定特別協定 (這裡即 *Iterable Protocol*)。

只要在 Prototype Chain 中提供任何符合迭代協定的實作方法，便賦予此資料型別「可迭代」的能力。

:::info
**Iterator**

所有 iterable 的資料型態都可以轉成 Iterator 的類別 (e.g., `.values()` 方法)，進而以此規範此 *Iterable Protocol* 之定義、實作，和使用 Iterator 的助手函式等。

**例如:** 在 Map 中欲調用 Array's instance 的 `.reduce()` 方法 (即定義於函式建構子的 `Array.prototype`)，必須先將 Map 轉換為 Array (`new Array()`) 再行操作。

```javascript=
const map = new Map([
  ["A", 1000],
  ["B", 1500],
  ["C", 2000],
]);

const total = [...map.values()].reduce((a, b) => a + b);
```

但實際上 Iterator 類別本身就有規範自己的 `.reduce()` 方法，所以不用轉換為 Array 也能使用，省去了中間冗於的 Array 物件建構，提升效能: 

```javascript=
const total = map.values().reduce((a, b) => a + b);
```

參考:
- [Symbol.iterator - MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/iterator)
- [Iterator - MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Iterator)
:::

:::info
**Iterable Protocol**

JavaScript 中符合 *Iterable Protocol* 的方法即為: 此無參數傳遞之函式執行後會返回一符合 `IteratorResult` 界面規範之物件，即: 物件中有以 \<next\> 為 key 的函式，其會返回裝載 \<value\> 和 \<done\> 的物件。

當每次迭代時，例如執行 `for...of`, `func(...)` 時，JavaScript runtime 便會嘗試調用該 Object 在 prototype 中指定的 Symbol.iterator 的方法，在每次迭代中呼叫 `.next()`，並將 \<value\> 指派給特定變數。

> 此 *Iterable Protocol* 也可選擇實作 `return()` / `throw()`，用以呼叫函式可提前進行返回清理程序 / 拋出例外並立即停止執行 (Generator 已內建實作)。

參考:
- [Iteration protocols - MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#the_iterable_protocol)
- [Spread syntax (...) - MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax)
- [for...of - MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of)
:::

#### 使用 Generator (function*)

:::warning
**注意:** `GeneratorFunction` 之物件建構式「可」接受參數，但符合 Iterable Protocol 的方法卻「不」接受參數 (e.g., `for...of` 沒有，也不需要可以傳遞 `GeneratorFunction` 構造參數的設計)。
:::

```javascript=
const Generator = function* (...arg) {
    // Only pure generator function can pass the arguments.
    console.log(arg);
    yield 1;
    yield 2;
    yield 3;
};
const obj = {
    [Symbol.iterator]: Generator
};

// or
const obj2 = {
    *[Symbol.iterator]() {
        yield 1;
        yield 2;
        yield 3;
    }
};

// class
class Foo {
    *[Symbol.iterator]() {
        yield 1;
        yield 2;
        yield 3;
    }
}

for (const value of obj);          // obj is iterable
for (const value of Generator());  // Generator "itself" is also iterable
[...obj2];                         // obj2 is iterable
console.log(...new Foo());         // Foo item is iterable
```

#### 使用自訂符合迭代協定的方法
```javascript=
const iterable_func = function() {
    let i = 0;
    console.log("Init the iterable function with Closure ...");

    return {
        next: () => {
            const value = `yield: ${i}`;
            const done = (i === 10);
            i++;
            return { value, done };
        }
    };
}
const obj = {
    [Symbol.iterator]: iterable_func
};

for (const value of obj);  // obj is iterable
```

### Symbol.asyncIterator
在 Prototype 中定義的保留靜態變數 `Symbol.asyncIterator`，用以識別、指定特別協定 (這裡即 *Async Iterable Protocol*)。

[Symbol.asyncIterator - MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/asyncIterator)

:::danger
欲在有 Symbol.asyncIterator 參與的迭代操作中，獲得在主線上阻塞效果，必須搭配使用有提供對應 `await` 方法的實作，如: `for await...of` 而不是 `for...of` / `forEach` (不作用)。
:::

```javascript=
const obj = {
    times: [1000, 1000, 1000],
    async *[Symbol.asyncIterator]() {
        for (const time of this.times) {
            await new Promise(r => setTimeout(r, time));
            yield `The async iteration await for ${time}`;
        }
    },
};

(async () => {
  for await (const result of obj) {
    console.log(result);
  }
})();
```

### Generator (function* / async function*)

一種協同式 (Coroutine) 協作多工 (Cooperative Multitasking) 的高階抽象機制，使應用層程式可以自行紀錄處理「當前階段性任務進度」: 可 ==yield== 讓出處理器使用權，並在之後可從工作未完處 ==resume== 恢復進度。

由 JavaScript 語法包裝、runtime 負責此在使用者層級做調度的機制，而不須仰賴作業系統高成本的 context switch 如 *Process* 或 *Thread*。並為符合 *Iterable Protocol* 之一的方法實作 (由其父類別 Iterator 之 prototype 規範，即 `[Symbol.iterator]()`)，可用於 iteration 這種階段式漸進完成任務。

> 如此在單執行緒中將多任務交織完成的 Coroutine 機制，也可透過 `async` / `await` 來實現同樣效果，並可與 Generator 互相組合搭配。

:::info
**GeneratorFunction**

JavaScript 沒有任何一個物件實體類別是對應「Generator」，只有 `GeneratorFunction` (Generator 的構造函式) 有確切物件類別歸屬，並繼承自 `Function` 物件。

而「Generator」是經由 `GeneratorFunction() {}.constructor` 產生的實體，因其 `constructor` 也有自己的 prototype，所以「Generator」所具備的正確 prototype 屬性應是 ==GeneratorFunction.prototype.prototype== (常被簡化為 `Generator.prototype`)。

參考:
- [GeneratorFunction - MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/GeneratorFunction)
:::

```javascript=
const Generator = function* (arg) {
    /*
     * Every next() starts/ends at yielding.
     */
    console.log(arg);   // 1st next() starts
    const a = yield 1;  // 1st next() stops / 2nd next() starts
    /* 
     * Because the 1st next() "stopped" at yield 1,
     * the value of a is assigned at the start of 2nd next(argument)
     */
    console.log(a);     // 'a'
    yield 2;            // 2nd next() stops / 3rd next() starts
    return 3;           // 3nd next() stops
                        // 4th & the following next() have nothing to run
};

const generator = Generator("Init value");
generator.next();     // 1st next() yields { value: 1, done: false }
generator.next('a');  // 2nd next() yields { value: 2, done: false }
generator.next();     // 3rd next() yields { value: 3, done: true }
generator.next();     // 4th next() yields { value: undefined, done: true }
```

#### 使用 Generator 實作 Coroutines

- **單執行緒上的 Coroutines (function\*)**
    [function* - MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*)

    ```javascript=
    const Coroutine = function*(name) {
        let i = 0;

        // Cooperative Coroutine Process
        while (true) {
            yield `Coroutine: ${name} has processed: ${i++}`;
        }
    };

    const coroutines = [
        Coroutine("Stream"),
        Coroutine("Read Files"),
    ];

    for(let i = 0; i < 100; i++) {
        coroutines.forEach(coroutine => {
            // Iterable Protocol
            const result = coroutine.next().value;
            console.log(result);
        });
    }
    ```

- **多執行緒上的 Coroutines (async function\*)**
    [async function* - MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function*)

    ```javascript=
    const AsyncCoroutine = async function*(name, is_await) {
        let i = 0;
        const sleep = async () => new Promise(r => setTimeout(r, 1000));

        // Cooperative Coroutine Process
        while (true) {
            if (is_await) {
                // Coroutine that uses await
                await sleep();
                const result = `Coroutine: ${name} has processed: ${i++}`;
                yield result;
            } else {
                // Coroutine that returns a Promise
                const promise = sleep();
                const result = `Coroutine: ${name} has processed: ${i++}`;
                yield promise.then(() => result);
            }
        }
    };
    ```

    - **使用 async / await 語法:**
        ```javascript=
        // Coroutines with async/await
        const async_coroutines = [
            AsyncCoroutine("I/O Multiplexing", true),
            AsyncCoroutine("HTTP Request Handling", true),
        ];

        (async () => {
            while (true) {
                for await (const async_coroutine of async_coroutines) {
                    // Async Iterable Protocol
                    const result = (await async_coroutine.next()).value;
                    console.log(result);
                }
            }
        })();
        ```

    - **使用 Promise 回呼:**
        ```javascript=
        // Coroutines with Promises
        const async_coroutines = [
            AsyncCoroutine("Async Read Files", false),
            AsyncCoroutine("Async Write Files", false),
        ];

        const async_coroutine_handler = (async_coroutine) => {
            // Async Iterable Protocol
            const result = async_coroutine.next();
            result
                .then(({ value }) => {
                    console.log(value);
                    async_coroutine_handler(async_coroutine);
                })
                .catch(e => console.error(e));
        };

        // Init async_coroutines
        for (const async_coroutine of async_coroutines) {
            async_coroutine_handler(async_coroutine);
        }
        ```

更多:
- [Coroutines in Javascript - Lorenzofox's dev blog](https://lorenzofox.dev/posts/coroutine/)
- [Coroutines and web components - Lorenzofox's dev blog](https://lorenzofox.dev/posts/component-as-infinite-loop/)

### Proxy
類似於「代理模型」的概念，透過多一層的資料結構包裝，作為支持修改物件底層內部方法的手段，可以此更改、擴充 JavaScript 語言預設行為，例如: 擴充對物件操作之記錄、驗證、溝通方法等。

Non-primitive 的物件資料結構中的內部方法有: `getPrototypeOf()`, `setPrototypeOf()`, `isExtensible()`, `preventExtensions()`, `getOwnPropertyDescriptor()`, `defineProperty()`, `has()`, `get()`, `set()`, `deleteProperty()`, `ownKeys()`。

這些都可以透過 Proxy 對物件預設行為進行修改。

[Proxy - MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy)

#### Handler
欲更改原有的物件內部方法，必須提供相對應的 handler (或叫 *trap*，因其類似於作業系統中 trap 進 kernel 概念，以此方式進行額外作業)。

```javascript=
const target = { a: 1 };
const handler = {
    /*
     * For example,
     * modify the "get" default internal function behavior.
     */
    get: (target, name) => {
        return `${name}: ${name in target ? target[name] : "default"}`;
  },
};

const proxy = new Proxy(target, handler);
console.log(proxy.a, proxy.b);  // "a: 1", "b: default"
```

:::warning
**JavaScript 不保證所有有關 Prototype 的操作行為！**

就如這裡 `Proxy` 所示範，任何 `Object` 內部 prototype 的方法都可以透過其來重新定義 ---- 就連原生物件的內部方法也可覆寫。

> 相較原生物件有不同內部方法定義之物件稱作: *Exotic Objects*。

**例:**
```javascript=
const targetArr = [1, 2, 3, 4, 5];
const handler = {
    get(target, prop, receiver) {
        if (prop === "length") {
            return "custom length";
        }
        return Reflect.get(target, prop, receiver);
    }
};

const arr = new Proxy(targetArr, handler);

console.log(Array.isArray(arr));  // true
console.log(arr.length);          // "custom length"
```
:::

更多:
- [Proxy pattern - Wiki](https://en.wikipedia.org/wiki/Proxy_pattern)
    ![image](https://hackmd.io/_uploads/ryHkiljM1g.png =400x)

    概念 pseudocode:
    ```javascript=
    class RealSubject {
        request() {
            // Real subject is doing operations ...
        }
    }
    class Proxy {
        constructor(real_subject) {
            this.real_subject = real_subject;
        }

        request() {
            // Handler operations before proxying real operations.
             ...
            this.real_subject.request();
            // Handler operations after proxying real operations.
            ...
        }
    }

    const real_subject = new RealSubject();
    const proxy = new Proxy(real_subject);
    proxy.request();
    ```

更多:
- Python 中類似機制的 CPython 底層實作: [【python】你知道描述器是多么重要的东西嘛？你写的所有程序都用到了！ - 码农高天](https://www.youtube.com/watch?v=Fp7aQO3QuS0)


### Reflect
*"Reflect its own characteristic."*

:::warning
**程式碼、數據自省 (introspection, reflection)**

Runtime 下，可根據場景需要動態反應、改變數據的解釋方式或程式碼的運行邏輯。
:::

同 Proxy 可將 Object 中可變更之內部方法替換效果。最主要用途是在 Proxy 的 handler 中 *forward* 內部預設方法。

[Reflect - MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect)

### Prototype

為 Non-Primitives (在 JavaScript 中全以 Object 實作) 複雜資料結構之代表屬性。

:::info
**Prototype Chain**
JavaScript 以 `[[prototype]]` 鍵值代表一物件之 prototype 資料型態，其指向另一個物件資料結構 (而此物件同樣也有自己的 `[[prototype]]` 鍵值，因此連鎖串起了 prototype chain):

```javascript
function Obj() {}
Obj.prototype = { name: "Obj prototype" };

const obj = new Obj();
console.log(obj.__proto__);            // Obj.prototype
console.log(obj.__proto__.__proto__);  // Object.prototype
```

而在一物件 instance 的 Prototype Chain 上存在任何 prototype 的 properties 資源，都可層遞的被此 instance 存取到 (由下往上游尋找)，如:

```javascript=
const parent_prototype = {
    public_func() { console.log("Parent"); },
    parent_func() { console.log("Parent"); },
};
const child_prototype = {
    public_func() { console.log("Child"); },
    child_func()  { console.log("Child"); },
};
const child = {};

Object.setPrototypeOf(child_prototype, parent_prototype);
Object.setPrototypeOf(child, child_prototype);

child.child_func();   // Child
child.parent_func();  // Parent
child.public_func();  // Child
```

:arrow_right: 關於 prototype chain 對 JavaScript 性能之影響請往下參考「*JavaScript 缺點*」節。 
:::

- [Object prototypes - MDN Web Docs](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object_prototypes)
- [Function: prototype - MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/prototype)
- [Object.prototype.constructor - MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/constructor)

<!-- :warning: -->

#### \_\_proto\_\_
系統內部對物件 prototype 之實作。

由於 Object 只是一個具多個 key-value pairs 的資料結構，各家 JavaScript 執行環境 (e.g., browsers, node.js) 約定俗成以 `__proto__` 鍵值 (或廣義上的 `[[prototype]]`) 指向該資料結構的父資料結構。

但 `__proto__` 是為供系統內部存取的 prototype 資料型態，理論上僅能由 JavaScript runtime 核心內部存取，開發者若需調用 prototype 建議使用 Constructor 的 `prototype` 鍵值以操作生成物件之 prototype chain，或使用 Object 對 `[[prototype]]` 操作的靜態函式界面。

:::info
**JavaScript's Boxing**
*動態語言特性*

當程式嘗試對 primitives 進行「類物件」操作時，例如:

```javascript
const car = "ford";
console.log(car.length);  // 4
```

> ![image](https://hackmd.io/_uploads/S1kbjljMkx.png =300x)
> 
> (Source: [Javascript Boxing and Unboxing - ikbal arslan](https://dev.to/ikbalarslan/javascript-boxing-and-unboxing-4o9g))

怪了，一個 string literal 怎麼會有 properties 呢? 原來，JavaScript runtime 會自動將如此對 primitives 的「類物件」操作以 boxing 包裝，臨時用「代表該屬性的 Object 資料型態」包裹 (e.g., *String*, *Array*, *RegExp*, ...)。所以就算是 primitives 也可存取到其 `[[prototype]]` 和 properties。
:::

但是有了 Boxing 機制，也造就了 JavaScript 奇怪現象:

:::warning
**Primitives 透過自動 Boxing 包裝成 Non-Primitives (Object) 型態**

```javascript
console.log("".__proto__.__proto__ === Object.prototype);  // true
```

*primitive 資料型態竟然能擁有 (更客觀的講「可存取」) non-primitive 的 prototype chain！*

這就難怪為什麼許多看似 Object 的 instances 可以直接使用的物件特性都必須使用 Object 靜態函式界面才能存取。因為除非 JavaScript runtime 又每次都對 `Object.prototype` 資源存取進行額外 type 檢查，不然因為 boxing 的特性，使 JavaScript 無法判斷是否是 non-primitive 在操作 `Object.prototype` 啊。

舉例: Object 的 `defineProperty()` 是「Object 靜態方法」而++不能++是「Object instance 方法」(由 `Object.prototype` 定義)。

> **編按:** 動態語言就是這麼的任性難伺候 ...
:::

常見使用範例:
- 使用 「Object 靜態函式界面」以修改該物件之 `[[prototype]]`:
    ```javascript=
    const prototype = {
        func() { console.log("prototype"); }
    };

    const obj = {};
    Object.setPrototypeOf(obj, prototype);

    Object.getPrototypeOf(obj);  // obj.__proto__ = prototype
    obj.func();                  // "prototype"
    ```
- 使用「Function Consructor」的 `prototype` 來指定其 instance 的 `[[prototype]]` 以實現 OOP 繼承:
    ```javascript=
    // Parent constructor
    function Parent(name) {
        console.log("Parent Constructor");
        this.name = name;
    }

    Parent.prototype.func = function() {
        console.log(`[Parent] ${this.name}`);
    };

    // Child constructor
    function Child(name) {
        Parent.call(this, name);
        console.log("Child Constructor");
    }

    // prototype chains with Parent
    Child.prototype = Object.create(Parent.prototype);
    // or
    Object.assign(Parent.prototype, parent);

    // overwrite constructor with Child's instead of Parent's
    Child.prototype.constructor = Child;

    Child.prototype.func = function() {
        console.log(`[Child] ${this.name}`);
    };

    // new instance of Child
    const child = new Child("child");

    child.func();                          // [Child] child
    console.log(child instanceof Child);   // true
    console.log(child instanceof Parent);  // true
    ```

#### Object.prototype
設定由 Object 所建構的 instance (`new Object()`) 都可以存取的資源。

#### Function.prototype
設定由 Function 所建構的 instance (`new Function()`) 都可以存取的資源。

- **call:** `func.call(execution_context, arg0, arg1, ...)`
- **apply:** `func.apply(execution_context, [arg0, arg1, ...])`
- **bind:** `func.bind(execution_context, arg0, arg1, ...)`

### Heap 資源是否已被回收釋放
可透過「Weak 指標」: 一可指向 Heap 裡尚存的物件，但不新增其 reference mark 的參考指標。來判斷該資源是否可被、已被 JavaScript runtime「動態回收」之依據。

> **注意:** Weak 指標是用來比對「物件變數所指向 Literal 的索引位址」，不是比對「物件變數存在 Stack 的變數位址」！

:::warning
「可」被回收之資源可由 `WeakSet`、`WeakMap` 來判定。

「已」被回收之資源可由 `WeakRef` 或設置 `FinalizationRegistry` 的 callback 來判定。
:::

#### WeakSet
[WeakSet - MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakSet)

```javascript=
const weak_set = new WeakSet();
let obj = {};

weak_set.add(obj);
weak_set.has(obj);  // true

obj = [1, 2, 3];
weak_set.has(obj);  // false (previous obj's reference is lost)

weak_set.add(obj);
weak_set.has(obj);  // true
```

#### WeakMap
[WeakMap - MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap)

```javascript=
const weak_map = new WeakMap();
let obj = {};

weak_map.set(obj, "obj");

weak_map.get(obj);  // "obj"
weak_map.has(obj);  // true

obj = [];
weak_map.get(obj);  // undefined
weak_map.has(obj);  // false
```

#### WeakRef
[WeakRef - MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakRef)

```javascript=
let cache = new WeakRef({ data: "cached data" });

function check_cache(cache) {
    let cachedData = cache.deref();
    if (cachedData) {
        console.log(cachedData.data);
    } else {
        console.log("Object has been garbage collected");
    }
}

check_cache(cache);
```

#### FinalizationRegistry
當 Object 即將被 JavaScript runtime 的 Garbage Collector 回收時，可用此 API 註冊被回收前的回呼函式。

- [FinalizationRegistry - MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/FinalizationRegistry)
- [WeakRef and FinalizationRegistry - JavaScript Info](https://javascript.info/weakref-finalizationregistry)

```javascript=
var registry = new FinalizationRegistry((msg) => {
    console.log(`GC Callback: ${msg}.`)
})

registry.register(target_obj, "callback_msg");
```

:::info
**註:** Chromium-Based 的瀏覽器可在 Devtool Window > Performance 強制觸發 JavaScript 引擎的資源回收處理程序。

![image](https://hackmd.io/_uploads/S1GGsloMJg.png =400x)
:::

### Object
JavaScript 以 prototype 為基礎來建立階層式的資料結構，以 Object 的 key-value 資料結構實作 prototype 機制 (e.g., 各類別中的 properties (value, methods) 等)。並可串起 Prototype Chain 實現繼承概念。

[Object - MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)

#### Properties
:::info
**[JS Engine 實作最佳化] 快速定位 Table 中的 Key Value Pair / Instruction 中內嵌最新一次 Query 資訊**

- **Shapes:** 透過「struct-like 模板」追蹤，從一 Object 之 transition chain 找出對應 key 之 offset。
- **Inline Caching:** 把最新一次操作參數 `obj.a` 的 offset 放在高階 WASM 裡，當下次參數還是 `obj.a` 時便可直接使用。

> 可一併搭配 compile-time 的 *monomorphisation* 實作: [What is monomorphisation with context to C++? - StackOverflow](https://stackoverflow.com/questions/14189604/what-is-monomorphisation-with-context-to-c)

[JavaScript engine fundamentals: Shapes and Inline Caches - Mathias Bynens](https://mathiasbynens.be/notes/shapes-ics)

- Basic property's inner struct:
    ![](https://hackmd.io/_uploads/SyiPGOAVgg.png =550x)

- Object property inner struct diff transition chain:
    ![image](https://hackmd.io/_uploads/Syma__AEll.png =550x)
    ![image](https://hackmd.io/_uploads/rJagrORVex.png =550x)
    ![image](https://hackmd.io/_uploads/HkU8SOAVge.png =550x)

- property look-up caching on function calls (like *PLT* ---- dynamic patch):
    ![image](https://hackmd.io/_uploads/BktWadRElx.png =550x)

- array (standard vs. optimiztaion):
    - table approach (standard):
      ![image](https://hackmd.io/_uploads/H1si6_AVee.png =550x)
    - vector approach (optimization):
      ![image](https://hackmd.io/_uploads/r1-Ka_AVge.png =550x)
:::

- [Object.defineProperty()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty)
    ```javascript=
    const obj = {};

    Object.defineProperty(obj, "property1", {
      value: 42,
      writable: false,
    });

    obj.property1 = 77;  // Won't change & throw an error in strict mode
    ```

- [Object.getOwnPropertyDescriptor()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertyDescriptor)
    ```javascript=
    const obj = {
      property1: 42,
    };

    const descriptor1 = Object.getOwnPropertyDescriptor(obj, "property1");

    console.log(descriptor1.configurable);  // true
    console.log(descriptor1.value);         // 42
    ```

#### Object 重組

- [Object.groupBy()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/groupBy)

    將 Object instance 以指定 key 進行分類，並依此回傳「新的」分類物件。

    ```javascript=
    const store = [
      { name: "asparagus", type: "vegetables", count: 5 },
      { name: "bananas", type: "fruit", count: 0 },
      { name: "goat", type: "meat", count: 23 },
      { name: "cherries", type: "fruit", count: 5 },
      { name: "fish", type: "meat", count: 22 },
    ];

    const result = Object.groupBy(store, ({ type }) => type);
    /*
     * {
     *     "fruit": [{...}, ...],
     *     "meat": [{...}, ...],
     * }
     */
    const result2 = Object.groupBy(store, ({ count }) => count ? "yes" : "no");
    /*
     * {
     *     "yes": [{...}, ...],
     *     "no": [{...}, ...],
     * }
     */
    ```

### Map
Map 為基本資料型別 Object 基礎之上的進階 key-value 資料結構。

:::info
**Map vs. Object**

相較 JavaScript 語言中所有 non-primitives (complex) 資料型態的底層基礎 ---- Object，Map 可視作更高階 key-value pairs，並提供超越 Object 的「Table 資料結構」所需的性質、功能:
- 任何資料型態皆可作為 key/value: primitives 或 non-primitives。
    > 對比 Object 僅能以 string 或 symbol 作為其 key。
- 保留 key 安插時的順序: 可用 `for..of` 循序遍歷。
- Map 內建維護 [Map.prototype.size](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/size) 值。
:::

- [Map - MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map)
- [Map vs Object in JavaScript - StackOverflow](https://stackoverflow.com/questions/18541940/map-vs-object-in-javascript)

```javascript=
const map = new Map([
    ['a', 0],
    ['b', 1],
]);

map.set('a', 1);

const obj = {};
map.set(obj, 2);
map.get(obj);  // 2
map.get({});   // undefined
```

### Set
擁有獨一 value 但沒有 key 索引的集合。並內建有兩兩集合之交集、聯集、差集 ... 方法。

[Set - MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set)

```javascript=
const set = new Set([1, 2, 3, 4, 5]);
const set2 = new Set([4, 5, 6]);

set.has(1);  // true
set.union(set2);  // Set(6) {1, 2, 3, 4, 5, 6}
```

## Web APIs
為實現和統一 Web 技術而訂定的網頁標準 (Web Standard)。

相關資源:
- [Web APIs - MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/API)
- [IDL Files - Webref - w3c](https://github.com/w3c/webref/tree/main/ed/idl)

> **註:** 但也可以直接從感興趣的系統框架去研究內部 `IDL` 規範，了解實際綁定可供調用的標準 API 有哪些。

### Web Workers
[The structured clone algorithm - Web MDN Docs](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm)

> The structured clone algorithm copies complex JavaScript objects. It is used internally when invoking `structuredClone()` to transfer data between Workers via `postMessage()`: storing objects with ++IndexedDB++, or copying objects for other APIs.
> 
> It clones by recursing through the input object while maintaining a map of previously visited references, to avoid infinitely traversing cycles.

[Transferring objects between threads - MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Transferable_objects)
```javascript=
// Create an 8MB "file" and fill it. 8MB = 1024 * 1024 * 8 B
const uInt8Array = new Uint8Array(1024 * 1024 * 8).map((v, i) => i);
console.log(uInt8Array.byteLength); // 8388608

// Transfer the underlying buffer to a worker
worker.postMessage(uInt8Array, [uInt8Array.buffer]);
console.log(uInt8Array.byteLength); // 0
```

## Platform APIs
可與 JavaScript 引擎綁定及互動之底層平台 API 實作。

### Web Browsers

:arrow_right: 詳見: [Anatomy of Web Browser Engines - shibarashinu](https://hackmd.io/@shibarashinu/H1wrAk4o0)

### Electron
使用 JavaScript (Node.js 平台 x V8 引擎驅動) 和 Chromium 前端 (Blink) 搭建的開源跨平台桌面級應用程式框架 (由 Microsoft GitHub 主導開發)。

*VS Code*、*Microsoft Teams*、*Slack*、*Discord*、*Figma*、*Twitch*、*WhatsApp* 等應用都採用 Electron 作為核心。

![image](https://hackmd.io/_uploads/r1UNoxofJg.png =400x)

相關資源:
- [Process Model - Electron](https://www.electronjs.org/docs/latest/tutorial/process-model)
- [Desktop App Development with Electron - Nishant Singh - Medium](https://nshnt.medium.com/desktop-app-development-with-electron-b27ac2b5d4d5)
- [Code Server: Using vscode via Web Browsers - Insu Jang](https://insujang.github.io/2019-11-10/code-server/)
- [VS Code Remote Development - VS Code](https://code.visualstudio.com/docs/remote/remote-overview)
    ![image](https://hackmd.io/_uploads/r1qQsgjM1g.png =400x)

### Node.js
專為 Web 伺服器打造的可執行 JavaScript 服務應用的跨平台後端系統框架，有獨自 Node.js 開發生態和套件管理系統 (npm)。

![image](https://hackmd.io/_uploads/B1s_sgiMkl.png =400x)
![image](https://hackmd.io/_uploads/SJgjjxiz1g.png =400x)
![image](https://hackmd.io/_uploads/r1GhsliMJe.png =400x)

相關資源:
- [Design overview - Libuv Docs](https://docs.libuv.org/en/v1.x/design.html)
- [An Introduction to libuv - nikhilm](https://nikhilm.github.io/uvbook/index.html)
- [[Series] The Internals of Node.js - Song Cho - Medium](https://bravochos.medium.com/the-internals-of-node-js-9def593c6082)
- [Thread Pool and OS Operations - Aman Dwivedi](https://www.scaler.com/topics/nodejs/thread-pool-and-os-operations/)



