點燈坊

學而時習之,不亦悅乎

發現 ECMAScript 本質

Sam Xiao's Avatar 2019-06-30

大家在學習 ECMAScript 時,是否覺得跟主流 OOP 程式語言不太一樣?為什麼沒有 Interface?為什麼很難使用 OOP Design Pattern ?為什麼我會從很討厭 ECMAScript 到很喜歡 ECMAScript?這要從其本質談起,因為我發現了其可愛一面。

Feature

ECMAScript 有兩大語言特色:

  1. ECMAScript 是動態語言
  2. ECMAScript 是以 function 為核心的語言

ECMAScript 是動態語言

  • ECMAScript 可輕易為 object 建立新 property,這在 C# 很難做到
  • ECMAScript 可輕易改變 變數型別,這在 C# 無法做到

這種動態特性好壞見仁見智:

優點:

  • 對於 library 開發者,動態特性可以實現很多黑魔法,如在 runtime 改變很多行為,Vue 就是善用這種特性
  • 程式碼精簡

缺點:

  • 對於 application 開發者,動態特性有太多黑魔法不容易維護
  • 太多行為都是 runtime 決定,不利於 static code analysis 分析與 refactoring

ECMAScript 族群也分兩派,一派很喜歡動態特型,另外一派則完全不使用其動態特性,此一族群最後會偏向 TypeScript

以我個人而言,若寫 application 時,我不太使用動態特性;若開發 library,為了 library 好用,會選擇性使用其動態特性

ECMAScript 是以 Function 為核心的語言

以下幾點可以證明 ECMAScript 是以 function 為核心的語言,而非 class:

  • ECMAScript 原型來自於 Scheme,而 Scheme 來自於 LISP,這都是典型的 functional programming language,而非從 C++ 或 Java
  • ES5 雖然有 class 觀念,但卻是利用 constructor function 模擬出來的
  • ES5 雖然有 inheritance 觀念,但卻是用 function prototype 實踐
  • ES6 雖然有 class 與 extends,但其本質仍然是 constructor function 與 function prototype

也就是 OOP 並非其核心價值,僅提供基本 OOP 支援,而且 ES6 之後發展,也沒再對 OOP 有更進一步支援,但對 FP 卻越來越完整

也就是 ECMAScript 對 OOP 支援僅屬 entry level,連 C# 1.0 都不如,這也是為什麼拿來寫 OOP design pattern 非常不便

ECMAScript 也沒打算對 OOP 有進一步支援,如 OOP 必備的 interface、generics 都不可能出現,因為這些都不是其核心價值,這也是為什麼會有 TypeScript 出現

ECMAScript 對 FP 支援則越來越完整,FP 代表性功能將陸續出現在未來版本中

ECMAScript 世界觀

ECMAScript 雖然也有 object,但其世界觀與 OOP 的 object 並不相同:

  • OOP:強調 資料功能 合一,都封裝在 class 內,以 class 為封裝最小單位,寫程式就是在寫 class,資料 就是 field,功能 就是 method,因為 field 的內容不同,因此有 object
  • ECMAScript:強調 資料功能 分家,資料 就是 object,功能 就是 function,以 function 為封裝最小單位,寫程式就是在寫 function,若要將資料封裝在 function 內,會使用 closure

也就是同樣是 object,OOP 認為 class 是 資料功能 的抽象,也因為有 功能,所以才必須要有 interface 定義 功能合約

但 ECMAScript 認為 功能 只放 資料 即可,功能 寫在 function 內,也因為 object 沒有 功能,所以不需要 interface 作為 合約

Q : ECMAScript 的 object 明明可以放 function,這與 class 的 method 不是很類似嗎 ?

ECMAScript 認為 Function as Data,也稱為 First Class Function,因此 function 可以如 data 傳進其他 function,也可如 data 回傳 function,甚至將 function 放在 array 中,也就是你怎麼處理 data,就能怎麼處理 function。

也因為 Function as Data,function 是被當成 data 掛進 object 中,只是 this 指向 object,而不是 class 的 method。

C# 雖然也可以將 function 傳到其他 function,但必須透過 delegate,也就是將 function 封裝成 delegate 物件後,才能提供類似 ECMAScript 功能,因為 C# 本質是 OOP

ECMAScript 與 OOP

ECMAScript 只是把 object 用在處理 data,而不是如 OOP 將 object 當成 抽象 使用,這是ECMAScript 與其他 OOP 語言最大差異。

這也是為什麼 OOP 的 design pattern 套用在 ECMAScript 都很奇怪,但 FP 的 design pattern 套用在 ECMAScript 都很順利。

因為 ECMAScript 本質是 FP,不是 OOP,而且也沒打算繼續往 OOP 邁進。

假如還是希望能以 OOP 寫 ECMAScript,那就要挑選 TypeScript,TypeScript 持續對 OOP 進行強化,也有 interface 與 generics

Conclusion

  • ECMAScript 的 object 僅用來處理 data,不是拿來當 抽象 使用
  • Funtion as Data,在 ECMAScript 中,function 被視為 data 使用
  • 由於 ECMAScript 語言特性不同,若以 OOP 去思考,就會很難進步,會覺得是很糟糕語言;但若以 FP 去思考,就會豁然開朗,會覺得是很棒語言