位元詩人 技術雜談:JavaScript 轉譯器百百種,孰優孰劣?

Facebook Twitter LinkedIn LINE Skype EverNote GMail Yahoo Email

程式設計者對 JavaScript 的態度是毀譽參半,喜歡 JavaScript 的開發者會說 JavaScript 跨越網頁前後端、桌面端、行動端、物聯網,儼然是大一統的程式語言,討厭 JavaScript 的開發者會說 JavaScript 坑坑洞洞超多,為了相容性,舊洞不修又再加新特性,根本就疊床架屋。開發者對 JavaScript 強烈的情感一部分是來自於 JavaScript 目前是網頁前端實質的 (de facto) 標準,是寫網頁程式的必然之惡。

為了能在保持相容性的前提下改善 JavaScript 先天不良的體質,使用 JavaScript 轉譯器 (JavaScript Trans-compiler) 就成了一個可行的方向。這類工具的思維在於減少手動撰寫樣板程式碼的時間,開發者可以用一個語法特性比較好的語言來開發程式,而把撰寫一些樣板程式碼的奇淫技巧委任由轉譯器處理;在理想上,這些轉譯器會將我們的程式碼轉為等效的 JavaScript 程式碼,省下手動寫原生 JavaScript 程式碼的眉眉角角。

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 較接近,且使用者較多,資料會好查一些