程式設計者對 JavaScript 的態度是毀譽參半,喜歡 JavaScript 的開發者會說 JavaScript 跨越網頁前後端、桌面端、行動端、物聯網,儼然是大一統的程式語言,討厭 JavaScript 的開發者會說 JavaScript 坑坑洞洞超多,為了相容性,舊洞不修又再加新特性,根本就疊床架屋。開發者對 JavaScript 強烈的情感一部分是來自於 JavaScript 目前是網頁前端實質的 (de facto) 標準,是寫網頁程式的必然之惡。
為了能在保持相容性的前提下改善 JavaScript 先天不良的體質,使用 JavaScript 轉譯器 (JavaScript Trans-compiler) 就成了一個可行的方向。這類工具的思維在於減少手動撰寫樣板程式碼的時間,開發者可以用一個語法特性比較好的語言來開發程式,而把撰寫一些樣板程式碼的奇淫技巧委任由轉譯器處理;在理想上,這些轉譯器會將我們的程式碼轉為等效的 JavaScript 程式碼,省下手動寫原生 JavaScript 程式碼的眉眉角角。
JavaScript 轉譯器的方案很多,一些實例如下:
- CoffeeScript
- TypeScript
- Babel (即 ECMAScript 6+)
- Elm
- Dart
- Transcrypt (Python 轉 JavaScript)
- Opal (Ruby 轉 JavaScript)
- GopherJS (golang 轉 JavaScript)
- ClojureScript (Clojure 轉 JavaScript)
這麼多方案,往往會不知如何選擇。本文會介紹一些常見的方案,讓讀者們參考。
CoffeeScript
CoffeeScript 算是早期 (西元 2009 年) 就投入此市場的轉譯器,但隨著更多轉譯器出現,CoffeeScript 的話題性 (hype) 已過,流行度逐年下滑。CoffeeScript 其實對 JavaScript 改善幅度不大,比較像是一種語法糖 (syntactic sugar)。最近改版的 CoffeeScript2 其轉譯目標改至 ECMAScript 2016,需依賴 Babel 再轉譯成現今主流的 ECMAScript 2015 語法,這種做法反而使專案複雜度上升。
- 風格:類似於 Ruby
- 型別:動態型別
- 物件:類別,單一繼承;無介面或 mixin
註:本節以 CoffeeScript2 為基準。
TypeScript
TypeScript 是目前 (2018 年四月) JavaScript 轉譯器裡最知名的方案,連 Google 的 Angular 新版中都優先使用 TypeScript 而非 Dart,可知 TypeScript 的名氣並非偶然。不過,TypeScript 其實不完全是 JavaScript 的超集合 (看這裡),還是把 TypeScript 當成一個獨立的語言來看比較好。TypeScript 主要的優勢是將 Java 或 C# 的優點帶到 JavaScript,因而受到許多開發者的喜愛。
- 風格:揉合 JavaScript 和 C#
- 型別:可選性的靜態型別;編譯期的型別檢查
- 物件:類別,單一繼承加上介面及 mixin
Babel
Babel 就是把新版的 ECMAScript 轉為現行的 ECMAScript 2015,算是在未來的 ECMAScript 完全普及前的一個過渡方案;由於標準建立到普及往往會有數年的落差,Babel 專案還是有其價值。以流行度來說,Babel 僅次於 TypeScript,但兩者有一段差距。Babel 搭配 Flow 可進行編譯期的型別檢查,但 Babel 對物件系統的改善較少,故受歡迎程度略遜一籌。
- 風格:JavaScript
- 型別:動態型別;可選性的型別檢查 (搭配 Flow)
- 物件:類別,單一繼承;無介面或 mixin
Flow
Flow 幾乎等於原生的 JavaScript,只是在編譯期加入型別資訊,用來改善 JavaScript 的弱點。Flow 通常和 Babel 一起使用,但也可以單獨使用。
Elm
Elm 的特色是強烈的函數式程式風格,和大部分的 JavaScript 轉譯器有所不同。由於函數式程式和物件導向程式的範式差距較大,通常是喜好 Haskell 或 OCmal 等語言的開發者會去用 Elm。
- 風格:帶型別的函數式程式,類似 Haskell
- 型別:強型別,有型別推斷等輔助功能
- 物件:使用 Records 來取代物件
Dart
Dart 原先的目標是直接取代 JavaScript,不過,由於政治上的考量,這個目標算是失敗了。目前 Dart 的主要方向調整為網頁前端 (AngularDart) 和行動端 (Flutter);以網頁前端來說,就是以 JavaScript 轉譯器的角度來切入。其實 Dart 語言本身設計得還不錯 (看這裡),但 hype 已過,故使用者較少。由於 Dart 在轉 JavaScript 時,程式碼會多出上千行的樣板代碼,對於較小的程式,用 Dart 反而不是最佳的選擇。
- 風格:揉合 JavaScript 和 C#
- 型別:可選性的靜態型別
- 物件:類別,單一繼承加上介面及 mixin
註:以 Dart 1.x 為基準。
Transcrypt
Transcrypt 是一個相對年輕的專案,其賣點就是可以用 Python 程式碼撰寫 JavaScript 程式。由於 Transcrypt 程式碼會編譯成 JavaScript 程式碼,會有一小部分程式碼及行為和原本的 Python 程式不同。由於這個專案相對年輕,目前使用人數較少,如果喜歡 Python 又需要寫網頁程式,可以考慮使用此專案。
- 風格:Python
- 型別:動態型別
- 物件:多重繼承,如同 Python
Opal
Opal 的賣點在於可以用 Ruby 程式碼寫 JavaScript 程式,為了相容於 JavaScript,會有一小部分行為和原本的 Ruby 略有不同,大體上 Ruby 的知識仍可沿用。雖然 Opal 的使用族群並不是很大,Opal 的專案目前仍活躍地維護著。
- 風格:Ruby
- 型別:動態型別
- 物件:單一繼承加上 mixin,如同 Ruby
敦優敦劣
由於 JavaScript 轉譯器選擇很多,每個開發者對語言的喜好各有不同,很難有一體適用所有開發者的方案。我們這裡僅提供一些思考的方向:
- 對於簡短的程式,直接寫原生的 JavaScript 即可
- 根據自己喜好的語言風格和特性來選擇
- 如果不知怎麼選,選 TypeScript 或 Babel,因這兩種語言和原生 JavaScript 較接近,且使用者較多,資料會好查一些