如何 0 成本启动全员 AI 技能提升?戳> 了解详情
写点什么

TypeScript 与 Haxe:两种截然不同的 JS 转译工具横向对比

  • 2015-08-10
  • 本文字数:3266 字

    阅读完需:约 11 分钟

JavaScript 无疑是当今最火爆的编程语言之一,它的崛起要归功于 AJAX、Node.js 的出现以及时下各种 MVC 框架的流行。但作为一门在十天之内创建出来的语言,JS 本身存在着一些不完善之处、以及容易令人疑惑的地方,例如不支持强类型以及 new 关键字的用法。尤其与当前主流的面向对象语言以及动态语言相比,其不足之处显得尤为突出。

为了克服 JS 语言中的缺陷,让更多的人能够编写出优秀的代码,市面上出现了大量能够将其它编程语言转译为JS 的工具。其中较知名的有 CoffeeScript Dart GWT Script#,以及本文的主角 TypeScript Haxe

TypeScript 是这一领域中的新贵,由微软于 2012 年发布。近期发布到 1.5 版,加入了大量 ES6 的特性。TypeScript 被设计为 JS 的一个超集,因此现有的 JS 都是合法的 TypeScript 代码。这门语言也得到了 Angular 团队以及 Telerik 的支持。

作为这一领域中的老前辈,Haxe 从 2006 年起就提供了转译为 JS 的功能。与 TypeScript 类似,Haxe 也提供了一套类似于 JS 的语法、静态类型系统以及模块。除了 JS 之外,Haxe 还能够提供编译为 Flash、PHP、C++ 等语言的功能。

来自 Haxe 的员工 Andy Li 最近在博客中对TypeScript 与Haxe 进行了一次全面的比较,包括语法、底层语义、类型系统、以及组织和生成代码的方式。为开发者如何在这两种工具间进行选择提供了一个不错的参考。

语法

TypeScript 与 Haxe 的基础语法是非常相似的,它们都支持在定义变量时声明类型。但 Haxe 在设计时引入了函数式编程的概念,因此 Haxe 中的大部分语法元素其实都是一种表达式,可以代表某个值。

// It is evaluated as the last expression inside it. // Here is an example that use try-catch expression together with block expressions. var result = try { var a = computationThatMayThrow(); finalComputation(a); } catch (exception:Dynamic) { rollBack(); defaultValue(); }另一个不同点表现在两者处理分号的不同。TypeScript 会自动在行末添加分号,因此不强制开发者使用分号。但这在 Andy 看来是一种极端错误的做法,它可能会带来意料之外的后果。而 Haxe 强制要求开发者在行末使用分号。

其它的一些语法差别还包括:

  • 两者都支持可选参数与剩余参数,其语法有细微的差别。
  • TypeScript 支持 ES6 中的箭头函数表达式,而 Haxe 的创造者 Nicolas Cannasse 则认为 Haxe 本身就具有表达式的特性,并且可以通过使用宏的 Haxe 类库实现相同、甚至更简洁的语法。
  • 两者对于函数返回类型的定义方式不同,TypeScript 使用的语法与箭头函数相类似,而 Andy 认为 Haxe 的语法有令人误解之虞
  • 两者在类与接口的定义语法上略有不同,TypeScript 提供了一种名为“参数属性”的语法糖以简化类的编写,而 Haxe 则需要通过宏才能够实现相同的语法。
  • 两者定义属性的 getter 与 setter 的语法截然不同,TypeScript 的方式较为直观,而 Haxe 的语法则相当独特。

Andy 认为总的来说,两者的语法具有高度的相似性,TypeScript 本身提供了许多用以简化代码的语法,而 Haxe 则可通过宏进行扩展,使特定表达式的语义产生转变。

语义

虽说 TypeScript 与 Haxe 在语法上非常近似,但它们在语义方面有着相当大的差距。首先两者对于变量的范围有着完全不同的定义,TypeScript 的变量范围与 JS 相同,通过 var 定义的变量作用于整个函数,而 Haxe 的变量范围与现代语言更为接近,变量的范围作用于一个代码块。

// TypeScript { var a = 1; } console.log(a); // ok, becauseaexist outside of a block // Haxe { var a = 1; } trace(a); // error: Unknown identifier : a在 Andy 看来,块范围的做法更适合于块结构的语言。实际上,JavaScript 的作者 Brendan Eich 也承认,当初选择以函数作为变量范围的做法是因为时间紧迫

其它一些语义方面的差别还包括:

  • TypeScript 对于 this 的处理方式与 JS 完全相同,在函数中的 this 具体指代的对象是动态决定的。而 Haxe 的作法与主流编程语言相似,this 总是指向当前类的某个实例。
  • 两种语言都定义了枚举类型,但 TypeScript 中的枚举只是一组有限值的集合,而 Haxe 中的枚举是一种强大的函数式编程结构,称为泛代数数据类型(GADT)。它更像是一种类型的有限集合,具有更为强大的处理方式。
  • 在 switch 语句方面,TypeScript 的处理方式与传统的 C 风格相同。而 Haxe 的 switch 实际上实现了函数式编程中的模式匹配。但 TypeScript 支持 ES6 中的解构赋值特性,能够一定程度上代替模式匹配的作用。

Andy 总结道,TypeScript 选择尽可能遵循 JS 标准的语义,因此如今的 JS 开发者能够很容易上手。而 Haxe 的做法是尽可能修复 JS 的设计缺陷,遵循当今主流语言的设计方式,因此对于不具备 JS 开发经验的用户更具吸引力,并且 Haxe 中引入了部分函数式编程的概念,它很好地与类似于 JS 的语法相容。

类型系统

TypeScript 与 Haxe 的基本类型非常接近,后者只是多了一个 Int 类型。两者都支持自定义类型,TypeScript 中可以使用类 / 接口及枚举,而 Haxe 中还多了 typedef 与 abstract 两个选择。

以下是 Andy 对两者的类型系统进行的一些具体比较:

  • TypeScript 使用了一种结构化的系统,所有类型都可以被表达为某个接口,只要是具有相同属性的类型都可以兼容。而 Haxe 的类型较严格,无法将匿名对象赋给某个类型化的变量。
  • 在 Haxe 中,Bool/Float/Int 之间不可进行隐式转换,除非使用 abstract
  • 两者都支持编译时类型推断,但 Haxe 要更强大一些,它能够从某个 var 变量首次使用时的赋值推断出其类型,而不仅仅限于其初始化时的值。
  • TypeScript 对于静态类型采取了比较宽容的态度,即使在代码中出现类型错误,依然能够编译为 JS 代码。而 Haxe 会直接报错,除非使用 untyped 关键字。
  • TypeScript 中有一些不严谨(但具有一定实用性)的设计。例如函数参数本应是逆变的,但在 TypeScript 中却是双变的

Andy 总结说,Haxe 的类型系统比 TypeScript 更为严格,但后者有时能够简化我们的工作。不过在他看来,如果出现了明显的类型问题,应当中止编译过程。Andy 认为这种宽容会造成开发者的滥用,这方面的一个例子就是 IE,它对语法错误的宽容让开发者逐渐地忽视了语法错误与 Web 标准。而 TypeScript 很不幸地继承了微软的这一传统……

代码组织与生成

TypeScript 的代码组织方式与 JS 一样灵活,在一个.ts 文件中可以包含语句、函数与类的定义,还可以使用三种模块系统,可以导出变量、函数与类型。

Haxe 的代码组织方式更像静态语言,不允许在顶层出现表达式(包括函数),只能包含在类型(主要是类)中。Haxe 程序的入口方法是某个用户指定类中的静态 main 函数。

在文件组织上,TypeScript 可以将.ts 文件放置在任意位置上。而 Haxe 的做法类似于 Java,其文件结构必须对应于包与模块的层次。

在代码生成时,Haxe 能够进行较多的高级优化功能,例如删除不可访问的代码,对函数进行内联等等。而 TypeScript 中的优化功能比较单一,主要是将一些高级语法特性转译为 ES3/5 所支持的 JS 语法。

Andy 在总结中表示,从代码的组织与生成来说,TypeScript 表现出较高的灵活性,更接近于 JS。而 Haxe 借鉴了主流编译型语言的经验,对于文件目录要求较严格。

结论

在文章的最后,Andy 对他的观点进行了一番总结。他认为这两门语言具有一定的相似性,但在设计思想上有许多不同之处。TypeScript 总体更接近原生的 JS,对于 JS 开发者来说更容易上手。而非 JS 开发者或许会喜欢 Haxe,它更接近于现代的静态语言,同时引入了许多函数式编程的概念,进一步加强了它的语法特性。

Andy 个人更偏向于使用 Haxe,除了因为他本身就是 Haxe Foundation 的一员之外,还因为 Haxe 能够提供编译为其它语言的功能,而这一点是 TypeScript 所不具备的,因为后者设计时就是为了编译为 JS 这个目的而生。


感谢魏星对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ @丁晓昀),微信(微信号: InfoQChina )关注我们,并与我们的编辑和其他读者朋友交流(欢迎加入 InfoQ 读者交流群)。

2015-08-10 19:374762
用户头像

发布了 428 篇内容, 共 196.8 次阅读, 收获喜欢 39 次。

关注

评论

发布
暂无评论
发现更多内容

【LeetCode】俄罗斯套娃信封问题Java题解

Albert

算法 LeetCode 28天写作

【经验分享】如何释放企业CMDB价值?——CMDB建设路径浅谈

嘉为蓝鲸

运维自动化 配置中心 CMDB 配置信息 配置管理

Golang 中的并发限制与超时控制

冯骐

并发 超时 Go 语言

迄今为止最好用的Flink SQL教程:Flink SQL Cookbook on Zeppelin

Apache Flink

flink

区块链产业革命:解决融资租赁之谜

旺链科技

区块链应用 融资租赁

史上最全整合第三方登录的开源库

happlyfox

OAuth 2.0 28天写作 3月日更

GitHub上获赞10万star的高并发神级进阶资料,面试官再问高并发问题请你把这篇文章发给他!

Java架构之路

Java 程序员 架构 面试 编程语言

四面阿里成功斩获offer,在此分享我的复盘经验总结!

Java架构之路

Java 程序员 架构 面试 编程语言

阿里P7亲自讲解!驱动核心源码详解和Binder超系统学习资源,跳槽薪资翻倍

欢喜学安卓

android 程序员 面试 移动开发

用 Go 写一个轻量级的 ldap 测试工具

冯骐

运维 开发 ldap Go 语言

Pgbouncer最佳实践:系列四

PostgreSQLChina

数据库 postgresql 软件 开源社区

在主动要求涨工资这事上,不要学我!从第一份工资800开始说起

四猿外

程序员 涨薪 工资 收入 跳槽

手把手教学,如何使用低代码快速构建应用程序步骤详解!

优秀

低代码

Open-Falcon 中的 LDAP 认证

冯骐

Python 运维 Open-Falcon ldap Go 语言

用 Go 写一个轻量级的 ssh 批量操作工具

冯骐

运维 SSH Go 语言

拍乐云加盟UCloud优云精选计划,构建云上的美好互动

拍乐云Pano

ucloud 云服务 RTC 拍乐云 白板

Nginx安装后要做的第一件事

运维研习社

nginx WEB安全

云安全和访问管理

龙归科技

云计算 安全 云端 企业安全

阿里P7亲自讲解!如何快速的开发一个完整的直播app,成功入职腾讯

欢喜学安卓

android 程序员 面试 移动开发

都 2021 年了,也该抛弃 ExpressJS 了

LeanCloud

大前端 nodejs 框架

神经网络攻防: 02.攻击模型的输出层

P小二

AIPwn AI安全 P小二 神经网络攻防

面试官:如何用SpringCloud从零设计一个大型电商平台?

Java架构追梦

Java 架构 面试 微服务 SpringCloud

Serverless 极致弹性解构在线游戏行业痛点

阿里巴巴云原生

Serverless 微服务 开发者 云原生 消息中间件

LeetCode题解:190. 颠倒二进制位,移动n,JavaScript,详细注释

Lee Chen

算法 大前端 LeetCode

思科设备漏洞 CVE-2018-0171 的快速修复

冯骐

Python 运维 安全 网络 交换机

《精通比特币》学习笔记(第一章)

棉花糖

区块链 读书笔记

用 Nginx 的 auth_request 模块集成 LDAP 认证

冯骐

Python nginx 运维 ldap 认证

神经网络攻防:03.使用API修改神经网络参数

P小二

AIPwn AI安全 P小二 神经网络攻防

交换机配置的自动备份与变更告警

冯骐

Python 运维 网络 备份 multissh

2021总结全网最新、最全、最实用Java岗面试真题!已收录GitHub

比伯

Java 编程 架构 面试 程序人生

软件开发,如何快速有效缩短项目周期

雯雯写代码

软件开发

TypeScript与Haxe:两种截然不同的JS转译工具横向对比_JavaScript_邵思华_InfoQ精选文章