JavaScript 筆記:從語言特性到函式編程
Wikipedia 對 JavaScript 的介紹
維基百科對 JavaScript 的描述為: 「JavaScript often abbreviated as JS, is a programming language that conforms to the ECMAScript specification. JavaScript is High-Level, often just-in-time compiled, and multi-paradigm. It has curly-bracket syntax, dynamic typing, prototype-based object-orientation, and first-class functions.」
上述解釋使用了許多專有名詞,因此本文先針對 JavaScript 的 1. High-Level、2. JIT Compiled、3. One Single Thread 特性進行整理,並延伸介紹其 First-class functions 與 Functional Programming 的特性。
1. High-Level Programming Language
High-Level 語言的語法更貼近人類思維,但需透過 Compiler 或 Interpreter 轉換成機器能理解的二進位碼 (0 與 1)。 與之對比,Low-Level 語言雖對人類較不直觀,但能直接與機器溝通,受硬體影響較大。
例如,C 屬於 Low-Level,需要手動管理記憶體;JavaScript 與 Python 屬於 High-Level,變數宣告時無須設定記憶體,代碼更易於撰寫,但失去了針對記憶體最佳化的能力。
2. Just-In-Time Compiled
上一段提到 High-Level 語言比較像人講的話,但電腦聽不懂,所以需要「翻譯」成電腦能理解的語言。這裡來說明一下,原始程式碼(Source Code)要怎麼被翻譯給電腦執行,主要有三種方式:編譯 (Compilation)、直譯 (Interpretation),還有 即時編譯 (Just-In-Time Compilation)。
-
Compiler:在執行前一次性將程式碼轉換成機器碼。 優點:執行快,可獨立運行;缺點:除錯慢。代表語言:C。
-
Interpreter:逐行轉譯並執行。 優點:靈活;缺點:速度較慢,需執行環境。代表語言:JavaScript。
-
Just-In-Time Compilation (JIT):結合上述兩者優點。 例如 Google 的 V8 engine 已導入 JIT,提升執行效率。
3. One Single Thread & Non-blocking Event Loop
One Single Thread 指的是 JavaScript 一次只能做一件事,會一行一行、照順序執行程式碼。我們可以從下面的程式碼看到,執行和呼叫的順序完全一樣,代表 JavaScript 處理事情是「排隊」來的。
有些人會以為,如果遇到需要花時間的任務(像是從 Google Map 取得地圖資料),後面的程式就會被卡住。其實不會,因為 JavaScript 有「事件循環(Event Loop)」這個機制,可以把需要等待的任務丟到背景處理,不會影響後續的程式繼續執行。
若遇到耗時任務(如 API 呼叫),JavaScript 透過 事件循環 (Event Loop) 將任務放入背景處理,避免阻塞後續程式。
4. 一級函式 (First-class Functions)
在 JavaScript 中,函式屬於一級函式,代表:
- 函式是物件,可存放於變數、物件、陣列。
- 函式可作為參數傳入另一個函式。
- 函式可以作為回傳值。
5. Functional Programming 特性
JavaScript 同時支持 物件導向編程 (OOP) 與 函式編程 (FP)。其中 FP 具備 宣告式 (Declarative) 的特性。
Imperative vs Declarative
寫程式有兩種常見風格:命令式(Imperative)和宣告式(Declarative)。命令式就是一步步告訴電腦怎麼做每個動作;宣告式則是直接告訴電腦我們想要什麼結果,讓電腦自己決定怎麼做。
Function Programming 的概念
函式編程 (FP) 具有宣告式 (Declarative) 的風格,基於將許多 "pure functions" 結合起來,並避免 "side effects" 以及 "mutating data" 。
-
Pure function 僅回傳輸出,不修改輸入資料,且避免 Side Effects。
-
Side effect 修改外部變數、進行 console logging、DOM 操作或發送 HTTP 請求。
-
Immutability 在函式編程裡,資料(State)不應該直接被改動。如果要改變 State,應該先複製一份,再修改這份複製品,最後把新的資料回傳回去。像在 React 和 Redux 裡,就很強調 State 不能直接改變這個原則。
簡單來說,寫函式編程時要盡量不要直接改變原本的資料,可以多用像 .map()、.filter()、.reduce() 這些不會影響原資料、也不會有副作用的內建方法來處理資料。