敬告:本文作者没写过上万行的代码,文中信息全部为道听途说,未经查证;文中观点可能偏颇狭隘一根筋,谨做抛砖引玉之用。望达者查之,读者自重,喷者迅猛。
Google 近日推出 Dart 语言,剑指大红大紫的JavaScript。为什么Google 挑了这个看着不软的柿子,Dart 能不能顺利推倒傲娇的 JavaScript,这篇文章主要分析这两个口水侧漏的问题。
JavaScript 和 Google 的蜜月
JavaScript 本来是 Netscape 的小打小闹,可作为网页动态脚本的开先河者,它第一个实现了对网页动态指指画画的功能,必然随着 Web 壮大而壮大。2005 年,AJAX 兴起,网络应用形胜,JavaScript 更是如日中天。尽管其它脚本语言(e.g.VBScript, Perl等)能实现相同功能,JavaScript 是唯一一个跨平台跨设备浏览器都支持的语言。知名科技 Blog 抠腚好弱甚至说,所有能用 JavaScript 实现的,必将被 JavaScript 实现。
回顾 AJAX 的兴起,Google 扮演了重要的推手角色。几个标志性网络服务 Gmail, Google Maps, Google Group,甚至 Google 搜索建议,都采用了 AJAX 实现。用户端无需安装任何插件,便有交互效果。榜样的力量是无穷的,Google 的服务充分展现了 AJAX 的潜力,之后就是大家一拥而上,将 AJAX 捧到聚光灯下。考虑到 JavaScript 在 AJAX 之前都是小打小闹,验证个表单什么的,被人认为不堪大用。如果当时你说自己会 JavaScript 都没人搭理你,怎么也要懂个 ASP/JSP 才拿得出手。当然也不是说 JavaScript 可有可无。就去年,我在网上订机票,把身份证号填成手机号,竟然就注册成功了,结果最后空姐不让我登机!妈的,2010 年了,在网页上加个 JavaScript 表单验证会死么?分辨身份证号码和手机号码是尼玛世界级难题么?跑题了,总之还是 Google 把 JavaScript 从小萝莉带入青春期。
AJAX 应用越来越多,JavaScript 代码越来越多,短板也暴露的越来越明显众所周知,评判编程语言的标准和评判男人的标准不一样。其中重要的一个标准是看编程语言有多快(严格地说,编程语言无快慢之分,编程语言的实现才有。为了语言简洁,本文用编程语言快慢代指。)。而 JavaScript 最大的问题是,太!慢!了!
作为脚本语言,没有事先编译,性能完全靠浏览器里的 JavaScript 引擎。Google 在芬兰找了一个团队,闭门造车两年打造出 V8 JavaScript 引擎,内置入 Chrome 浏览器。而 Chrome 在 08 年横空出世,用几百上千倍的 JavaScript 速度分数秒杀了当时市场上一切其它浏览器。自然,后来其它浏览器纷纷跟上,苹果搞了 Safari Nitro 引擎,Mozilla 更新了各种猴子 JavaScript 引擎,连 IE 也不甘落后,搞出 Chakan 引擎各种提速,这货虽说不比 Google Chrome V8 的速度,也聊胜于无。终于,JavaScript 引擎性能的突破使其能够满足现代网络应用部署的需要。这次,Google 把 JavaScript 从含苞待放的青春前期催熟到青春后期。
吊诡的是,如今推出 Dart 语言的团队便包含当年开发 V8 引擎的团队。他们对 JavaScript 的评价是:“JavaScript 语言与生具来的残疾是无法通过进化改善的。”
就是说,感情破裂了。
JavaScript 的非主流本质
究其原因,最大的瓶颈源于 JavaScript 是非主流语言的本质。
JavaScript 是基于原型(Prototype-based)的编程语言,而现在最主流的对象编程语言都是基于类(Class-based)的。两者根本的区别在于,迥异的视角产生的不同方法论。。。
不严谨地说,基于类的语言逻辑来自分类学(Taxonomy),自上而下进行实现。程序员先要理清楚各种类之间的关系,定义好各种类,才能写出类下面的实例(可用对象)。而基于原型的语言逻辑来自认知论,举一反三进行实现,更符合人类正常认知的模式。程序员先关注几个个例的具体行为,之后再分类使用。不恰当比喻说明,如果让基于类的语言写出一个男人,要先找到人类。然后创建一个男人子类,子类具有人类一切属性且有男性性征。之后在男人子类创建出具体的男人甲。而基于原型的语言,可以先观察女人和公猿,然后删删减减拼拼凑凑得到一个男人的原型,之后按照原形创建一个男人乙。
可以看出,基于类的编程主要方法是继承,男人子类继承了人类所有属性,男人甲拥有男人子类所有属性并赋了值,比如身高 175 体重 300 斤。而原型编程主要方法是克隆,男人原型克隆了女人的智商和皮肤属性,公猿的性腺和嗓音属性等等其它不细说了,请自行脑补。
计算机科学史上,先出现的是基于类的语言,后来才有基于原型的语言。前者在对象编程领域一直是主流,大学里教的主要是这个,多数研究也集中在这个领域。而原型编程,虽说由于 JavaScript 的存在使用的很多,但和基于类的编程相比还是非主流状态。这就导致了一些相对劣势。
由于缺乏对类的支持,而很多开发人员又习惯基于类编程。很多 JavaScript 库模拟了自己的类对象,便于开发人员调用。看上去现在两全齐美了,其实没有。关键问题是,性能。
拜 Google 所赐,JavaScript 拥有目前世界上最有技术含量最复杂的脚本引擎,速度和其它脚本语言相比无以匹敌。Google 对 JavaScript 的最主要提速来自 JIT(Just-in-time) 编译,把 JavaScript 预编译成机器码,在执行时直接调用机器码提升效率。可跟传统编译语言比起来,性能不可同日而语;甚至比 JAVA, C# 也略逊一筹。
事实上,JavaScript 引擎相当复杂,且提速越来越难。这也跟 JavaScript 非主流原型编程有关。
基于类的语言,同类实例的数据结构和方法都相同,男人甲乙丙丁都有身高体重胸围,无非是数值区别。这种情况下,脚本引擎只需要优化该类一次,生成本地码,之后反复套用,自然会有效率性能提升。
而原型语言不同,没有类的概念。传统原型语言引擎的经典方法是给出一个大字典(HashMap),每次调用具体数值都去查字典,如此操作费时费力。可如果引擎按照类语言进行预编译,又不知道编译出来的本地码后面是否被频繁调用。有时甚至得不偿失,花在预编译上的时间还未必比查字典少。Google 的 V8 引擎则另辟蹊径,分析发现 90% 的JavaScript object 是有规律可循的。于是他们总结规律,人为地生成隐藏类,对隐藏类进行优化编译。当扫描的符合条件 JavaScript 代码时,自动调用事先编译好的机器码执行。
现在你知道原型语言 JavaScript 为开发者和引擎造成了多大的拧巴。这种复杂性带来的维护成本上升,开发门槛提高。要是用了主流类语言,不会有这么多麻烦。
JavaScript 本身缺乏很多特性,如不支持 Static Typing,调试维护相对困难;调用多个第三方库难以保证不冲突;内置库太迷你等等等等。当然这些都有解决方法。事实是,大多数 JavaScript 的粉丝也承认,JavaScript 是有一些缺陷的。
于是有了 Google Dart 语言,最核心的特性 1)基于类 2)可选类型(支持 dynamic/static typing)3)丰富内置库 4)开发工具丰富。分别对应了上文提到的 JavaScript 缺陷。
下篇待续:Dart 的今生来世,主要分析 Dart 能否推倒青春后期的 JavaScript。
原文:http://www.guao.hk/posts/dart-vs-javascript-side-a-javascripts-legacy-problems.html
【编辑推荐】