發現 JavaScript 本質
大家在學習 JavaScript 時,是否覺得 JavaScript 跟主流 OOP 程式語言,如 C++ / Java / C# 不太一樣?為什麼 JavaScript 沒有 interface?為什麼 JavaScript 很難使用 OOP Design Pattern ?為什麼我會從很討厭 JavaScript 到很喜歡 JavaScript?
這要從 JavaScript 的本質談起,因為我看到了JavaScript 可愛的一面。
Feature
JavaScript 有兩大語言特色:
- JavaScript 是動態語言
- JavaScript 是以 Function 為核心的語言
JavaScript 是動態語言
- JavaScript 可輕易為 object 建立新的 property,這在 C#
很難做到
- JavaScript 可以輕易改變
變數型別
,這在 C#無法做到
這種動態特性是好是壞見仁見智:
優點:
- 對於 library 開發者,動態特性可以實現很多黑魔法,在 run-time 改變很多行為,Vue 就是善用 JavaScript 這種特性
缺點:
- 對於 application 開發者,動態特性有太多黑魔法不容易維護
- 太多行為都是 run-time 決定,不利於開發工具分析與重構
JavaScript 族群也分兩派,一派很喜歡動態特型,另外一派則完全不使用其動態特性,這一類族群最後會偏向使用 TypeScript (Angular、RxJS、VS Code)
以我個人而言,若寫 application 時,我不會使用動態特性;若開發 library,為了 library 好用,會選擇性使用其動態特性
JavaScript 是以 Function 為核心的語言
以下幾點可以證明 JavaScript 是以 Function 為核心的語言,而非 Class:
- JavaScript 雖然有 Java 字眼,但本質與 Java 完全不同,就如同
林志玲
與林志炫
的關係 (就是沒有關係) - JavaScript 原型來自於 Scheme,而 Scheme 來自於 LISP,這都是典型的 Functional Programming Language,而非從 C++ 或 Java
- ES5 雖然有 class 觀念,但卻是利用 Constructor Function 模擬出來的
- ES5 雖然有 Inheritance 觀念,但卻是用 Function Prototype 實踐
- ES6 雖然有 class 與 extends,但其本質仍然是 Constructor Function 與 Function Prototype
也就是 OOP 並非 JavaScript 的核心價值,僅僅提供最基本的 OOP 支援,而且 ECMAScript 2016 之後的發展,也沒再對 OOP 有更進一步的支援,但 ECMAScript 對 FP 的支援卻越來越完整
也就是 JavaScript 對 OOP 支援僅屬於 Entry Level,連 C# 1.0 都不如
而 JavaScript 也沒打算對 OOP 有進一步支援,如 OOP 必備的 Interface、Generics 都不可能出現在 ECMAScript,因為這些都不是 JavaScript 的核心價值,這也是為什麼會有 TypeScript 出現
但 JavaScript 對 FP 支援則越來越完整,FP 的代表性功能都將陸續出現在新版 ECMAScript 中
JavaScript 的世界觀
JavaScript 雖然也有 物件
,但其世界觀與 OOP 的 物件
並不相同:
- OOP:強調
資料
與功能
合一,都封裝在 class 內,以 class 為封裝的最小單位,寫程式就是在寫 class,資料
就是 field,功能
就是 method,因為 field 的內容不同,因此有 object - JavaScript:強調
資料
與功能
分家,資料
就是 object,功能
就是 function,以 function 為封裝的最小單位,寫程式就是在寫 function,若要將資料封裝在 function 內,會使用 closure
也就是同樣是
物件
,OOP 認為 class 是資料
與功能
的抽象,也因為有功能
,所以才必須要有 interface 定義功能
的合約
但 JavaScript 認為
功能
只放資料
即可,功能
寫在 function 內,也因為 object 沒有功能
,所以不需要 interface 作為合約
Q : JavaScript 的 object 明明可以放 function,這與 class 的 method 不是很類似嗎 ?
JavaScript 認為 Function as Data
,也稱為 First Class Function
,因此 function 可以如 data 傳進其他 function,也可如 data 回傳 function,甚至將 function 放在 array 中,也就是你怎麼處理 data,就能怎麼處理 function。
也因為 Function as Data
,function 是被當成 data 掛進 object 中,而不是 class 的 method。
C# 雖然也可以將 function 傳入到其他 function,但必須透過 Delegate,也就是將 function 封裝成 Delegate 物件後,才能提供類似 JavaScript 功能,因為 C# 本質是 OOP
JavaScript 與 OOP
JavaScript 只是把 物件
用在處理 data,而不是如 OOP 將 物件
當成 抽象
使用,這是 JavaScript 與其他 OOP 語言最大的差異。
這也是為什麼 OOP 的 Design Pattern 套用在 JavaScript 都很奇怪,但 FP 的 Design Pattern 套用在 JavaScript 都很順利。
因為 JavaScript 的本質是 FP,不是 OOP,而且 ECMAScript 也沒打算將 JavaScript 繼續往 OOP 邁進。
假如還是希望能以 OOP 寫 JavaScript,那就要挑選 TypeScript,TypeScript 持續對 OOP 進行強化,也有 Interface 與 Generics
Conclusion
- JavaScript 的 object 僅用來處理 data,不是拿來當
抽象
使用 Funtion as Data
,在 JavaScript 中,function 被視為 data 使用- 由於 JavaScript 語言特性不同,若以 OOP 語言,如 C++ / C# / Java 思維去思考 JavaScript,就會很難進步,會覺得 JavaScript 是很糟糕的語言
- 但若以 FP 語言,如 F# / ReasonML / Haskell 思維去思考 JavaScript,就會豁然開朗,會覺得 JavaScript 是很棒的語言