技术杂谈:JavaScript 转译器百百种,孰优孰劣?

PUBLISHED ON APR 10, 2018

    程序设计者对 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 较接近,且使用者较多,数据会好查一些
    你或许对以下产品有兴趣