为什么Javascript需要类型?

VICTOR SAVKIN认为像Javascript和Ruby这样的动态脚本语言最好有类型,他在WHY JAVASCRIPT NEEDS TYPES一文中认为:

类型曾经有坏的名声,因为其使得代码能以阅读,增加不必要的仪式与复杂性,但是在这个博文中我想说明,一个做得正好的类型系统能够使得代码更加可阅读和工具化,而且非但没有影响语言的表达能力。

类型其实是对人和机器的文档
让我们看看类型注释是如何既对人或机器(计算机)都是有用的文档,看看下面函数jQuery.ajax(),假如我们并不熟悉它,那么我们从这个方法签名中能得到什么信息呢?
jQuery.ajax(url, settings)

我们唯一能肯定的是,该函数接受两个参数。 我们可以猜出其类型,也许第一个是一个字符串,第二个是一个配置对象。 但这只是一个猜想,我们可能是错的。 我们不知道进入设置对象有哪些选项(因为既没有他们的名字也没有他们的类型)或这个函数返回什么我们也不知道。

如果我们没有检查这个函数的源代码和文档,我们是没有办法调用这个函数的。 但是检查源代码并不是一个好的选择,使用函数和类的目的就是能够不知道他们是如何实现的前提下使用它们。 换句话说,我们应该依靠它们的接口,而不是实现。 因此,源码不能检查了,那么我们这里唯一的选择是检查文档。 这样做并没有什么错。 但它需要时间。

对比类型版本:


ajax(url: string, settings?: JQueryAjaxSettings): JQueryXHR;

interface JQueryAjaxSettings {
async?: boolean;
cache?: boolean;
contentType?: any;
headers?: { [key: string]: any; };
//...
}

interface JQueryXHR {
responseJSON?: any;
//...
}

它给予我们更多信息:

1.这个函数的第一个参数是一个字符串。
2.设置参数是可选的。 我们可以看到能传递到函数所有的选项,不仅有他们的名字,也有他们的类型。
3.函数返回一个JQueryXHR对象,我们可以看到它的属性和功能。

这就回到之前观点:
类型能够作为程序员的文档。

此外,这些信息能激活先进的自动完成功能,导航功能和重构能力。 这样的工具几乎是大型的项目必备要求。 没有他们程序员会害怕改变代码,这使得大规模重构变得几乎不可能。 理论上来说,您可以使用动态语言构建一个大型应用程序,但是你不能维护它。 因为没有先进工具的大型代码库总是semi-read-only只读(banq注:供技术鉴客欣赏赏玩)状态。类型能够激活先进的工具。

类型为程序员提供了一个概念性的框架
定义良好的接口意味着是好的设计。 因为它很容易表达想法。

例如,想象一个购书的应用程序,购买可以是两种角色来完成,一种是通过UI注册的用户,还有一种角色是外部系统通过一个API访问。


如您所见,类class扮演了一个购买者的角色。尽管角色对于这个应用程序非常重要,但是购买者这个角色概念在代码中没有明确表达了。也没有一个文件名为 purchaser.js 。 结果,有人修改代码后,很有可能错过角色这个曾经存在过的事实。修改后代码如下:


function processPurchase(purchaser, details){
}

class User {
}

class ExternalSystem {
}

只是通过查看代码很难知道哪个对象扮演了一个购买者的角色,以及这个角色有什么方法。 我们确定我们不会从工具中能得到太多的帮助。 我们必须手工人工推断出这些信息,这是缓慢且容易出错

现在我们和一个明确显式定义了Purchaser接口的代码比较:


interface Purchaser {
id: int;
bankAccount: Account;
}

class User implements Purchaser {}
class ExternalSystem implements Purchaser {}

这个类型版本清楚表明,我们有Purchaser接口,和User以及ExternalSystem类实现这个接口。 这就引出了我的下一个点。

类型对于定义接口/协议/角色等是有用的,它们为编程者提供一个概念性框架。

重要的是必须意识到,不强迫我们引入额外的抽象类型。 Purchaser抽象其实已经在这个JavaScript代码中存在,只是是没有被显式化,也就是被明确定义而已。

我花了大部分职业生涯使用Ruby和JavaScript编程,我发现这些语言非常强大和灵活。 但用这些语言编写相当大的应用程序后,我得出结论,接口的缺乏会推动开发人员建立紧耦合的系统。

在静态类型语言中使用接口定义子系统之间的界限。因为Ruby和JavaScript缺乏接口,界限就不太能用代码表示。 因此不能清楚地看到边界,开发人员开始只能根据具体类型而不是抽象接口。 它会导致紧耦合。在这些语言中构建大型解耦系统是可能的,但它需要大量的纪律。


似乎我是提倡静态类型的语言,但我不是。反对强制性的静态类型系统理由仍然很充分:

1.它使语言复杂化。 在JavaScript编写一个模拟mock库是一种几乎所有人都能实现的练习,但是在Java中做类似的东西是很困难的。
2.它限制了语言的表现力。
3.它需要类型注解,即使他们并不可取,比如使用领域特定语言DSL。

我们想要的是结合动态类型语言的强大和显式接口和类型注解的好处。

可选的类型系统

一个可选的类型系统不必须使用类型注解。类型注解是用来帮助你表达你的意图和获得更好的工具。

可选的类型系统是宽容的。你不必满足类型检查器。恰恰相反,类型检查器可以帮助你找到错误,搜索和重构。 你不需要完全重写程序以使类型正常运行。 如果你想使用原型和duck typing,就不要使用类型了。 只有当他们能增加价值时使用它们。

也并不是说,可选的类型只是好东西没有任何缺点。 它还是给语言增加了一些复杂性(相比一个强制性的静态类型系统)。 同时,充分看到这样一个系统的好处你就需要比纯文本编辑器更复杂的工具。我认为这是值得的。

类型化的Javascript
我在写这篇博客之前一段时间,也曾经呼吁“我希望Ruby有接口”。 那时我是一个Rails开发人员。因为我非常沮丧地工作在一个非常大的Rails代码库,一些重构需要花数月才能完成。 因为没有看到Ruby会有一个可选的类型系统的希望,所以这是一个嘴上的咆哮而已。

但是这一次是不同的。JavaScript社区在拥抱可选类型的想法。 TypeScript 已成为一个在许多公司用于生产的健壮工具。 AtScript , Flow也是这一领域的新项目。 我真的很兴奋地看好类型JavaScript社区在以后几年的未来。



[该贴被banq于2014-11-23 19:09修改过]

早该有类型了。。。TypeScript不就是为了这个而生的么。。。
其实类型过强的确不好,但是向强类型系统加入一个弱类型的类型的话情况就完全不同了,像C#的dynamic和Go的interface{}。
不但能让开发者享受强类型的便捷和可读,而且在必要时刻能使用若类型来处理类似数据这样的集合。

可选类型系统是个好特性。

可选类型系统是个好特性。