1.4 语言的进化

1.4.1 Qomo的重生

这时的Qomo已经相当完整地实现了一门“高级语言”的大多数特性,我一时间却觉得Qomo失去了它应有的方向。原本作为产品的一个组成部分的WEUI是有着它的商业目的的,而Qomo v1.x~v2.0的整个发展过程中也有着“开源框架”这样的追求。但当这些目的渐渐远去的时候,Qomo作为一个没有商业和社区推动的项目,该如何发展呢?

我已经不止一次地关注到了Qomo核心部分的复杂性。在Qomo v2以前,这些复杂性由浏览器兼容、代码组织形式和语言实现技术三个方面构成。举例来说,考虑到Qomo的代码包可以自由地拼装,因此Interface层的实现就必须要能够完整地从整个框架中剥离出去;另一方面,Interface层又必须依赖OOP层中所设计的对象实现框架。这使得Qomo v2不得不在Loader框架中加入了一种类似编译器的“内联(Inline)”技术,也就是在打包的时候,将一些代码直接插入指定的位置,以黏合跨层次之间的代码实现。

Inline带来的恶果之一,就是原本的Object.js被分成了9个片断—当使用不同的选项来打包的时候,这些片断被直接拼接到一个大的文件中;当使用动态加载方式装入Qomo的时候,可以用“Inline”的方式在使用eval()执行代码文本的同时插入这些片断。

我意识到我在触碰一种新的技术的边界。这一技术的核心问题是:一个框架的组织原则与实现之间的矛盾。

Qomo到底应该设计为何种框架?是为应用而设计,还是仅仅围绕语言特性的扩展?在不同的选择之下,Qomo又应该被实现成什么样子?

在2007年年末,我开启了一个新的项目,名为QoBean。QoBean是一个迷你版的Qomo,详情可参见Git仓库(aimingoo/qobean)。

1.4.2 QoBean是对语言的重新组织

QoBean将问题直接聚焦于“语言实现”,开始讨论JavaScript语言自身特性的架构方式、扩展能力以及新语言扩展的可能性。缘于这一设定,QoBean将Qomo中的语言层单独拿了出来,并设定了一些基本原则:

■ 不讨论浏览器层面的问题。

■ 在ECMAScript规范的基础上实现,以保证可移植性。

■ 可以完全、透明地替换Qomo中的语言层。

■ 从语言原子做起。

“从语言原子做起”意味着它必须回归到对JavaScript语言的重新思考,即究竟什么才是JavaScript语言的“原子”。

“语言原子”这个词我最早读自李战的《悟透Delphi》。李战,早期Delphi社区的活跃者,现任职于阿里软件资深架构师。不过这本书终究没出,而李战兄后来写了一本《悟透JavaScript》,算是完成了他的“悟透”。至于引发我关于JavaScript原子问题思考的,则是在本书第一版出版的前后,与宋兴烈宋兴烈,北京起步软件有限公司总工程师、联合创始人,长期从事IDE开发工具、编译器、虚拟机、基础平台的研究和开发工作。谈到JavaScript的一些特性,而他便提议将这些东西视作“原子特性”。

“这些东西”其实只有两个,其一是对象,其二是函数。它们初次在QoBean中的应用,便是“以极小的代价实现Qomo的整个类继承框架的完整体系”。而这一尝试的结果是:原本在Qomo中用了565行代码来实现的Object.js,在QoBean的描述中却只用了20行代码。进一步地,在新的QoBean中,为OOP语言层做的概念描述也只剩下了两行代码:

元语言的概念在Qomo/QoBean中渐渐浮现出来。2008年7月,即在发布QoBean alpha 1之后的半年,我为QoBean撰写了两篇博客文章:QoBean的元语言系统(一)、(二)。QoBean也在此时基本完成了对“Qomo的语言层”的重新组织。

事实上,QoBean本质上探讨了JavaScript这门语言的一种扩展模式,即基于语言自身的原子特性进行二次实现的能力。这与后来的其他一些语言扩展,尽管行进在完全不同的道路上,但却有着基本相同的目的。

我们在探索的是JavaScript这门语言的边界。

1.4.3 JavaScript作为一门语言的进化

JavaScript之父Brendan Eich曾说:“我们最初利用JavaScript的目的,是让客户端的应用不必从服务器重新加载页面即可回应用户的输入信息,并且给脚本编写者提供一种功能强大的图形工具包。”这包括要在客户端实现的两个方面的功能,第一是用户交互,第二是用户界面(UI)。而展现与交互,正是现在对“前端职能”的两个主要定义。所以这门语言的最初构想,与它现在所应用的主要领域是悄然契合的。

但在2000年之后,浏览器取代传统的操作系统桌面渐渐成为热门的“客户端”解决方案,AJAX在这时作为一种客户端技术对这一技术选型起到了推波助澜的作用。与此同时,开发人员觉察到JavaScript作为一门语言—在客户端实现技术中—难以有足够丰富的实现能力。于是语言级别的扩展纷纷出现:在代码组织上,开始有了名字空间;在运行效率上,有了编译压缩;在标准化方面,有了Common JS;在语言扩展上,有了在JavaScript中嵌入的解释语言……

对于传统的高级程序设计语言来讲,这一切再自然不过了。然而JavaScript毕竟只是一种脚本语言,这些“附加的”扩展与“第三方的”实现事实上带来了更大的混乱。于是大公司开始提出种种“统一框架”,或者兼容并包的“整合方向”。在这一选择中,大公司首先解决的是“自己的”问题,这是由于在它们的种种产品、产品线中尤其需要这样一种统一的、标准的方案,以避免重复投入带来的开发与维护成本。因此,“商业化产品+自主的JavaScript开发包”成为一种时兴的产品模式。在这一产品模式中,由于JavaScript本身不具有源码保护的特性,因此源码开放既是战略,又是手段,也是不得已而为之的事。

现在我们有了机会看到Plam手机平台上完整的Web OS的代码,也有机会直接读到FireBug中全部用于支持引擎级调试的代码,手边还有类似YUI、Dojo等的企业级框架可用。然而,一切还是一如既往的混乱。因为,这一切只是基于语言的扩展,而非语言或其基础库中的特性。造成这一事实的原因,既源于JavaScript自身初始设计的混合式特性,也因为ECMA在这门语言的标准化工作上的滞后与反复。

JavaScript在发布v1.0的时候,仅有结构化语言的特性以及一些基础的面向对象特性(即structured and object based programming)。到v1.3时有了本质性的改观,使得这一语言成为包括动态语言、函数式语言特性在内的特性丰富的混合语言。这一切被ECMA通过标准化的形式确定下来,形成了以JavaScript 1.5和ECMAScript Ed3版本(即JS1.5/ES3.1)为代表的,一直到我们今天仍在使用的JavaScript语言。

随后ECMA启动了一个工作组来进行下一代JavaScript的标准化工作,称为ECMAScript Ed4(即ES4/JS2),这个小组的工作始于2003年3月。然而它们搞砸了整件事,它们几乎把JS2设计成了一门新的、大的、复杂的语言。因此,一方面一些需要“丰富的语言特性”的厂商不遗余力地推进着这一标准,另一方面它又被崇尚简捷的前端开发人员诟病不已。迟至2009年年底,ECMA Ed4的标准化小组终于宣布:ES4的标准化暂停,并将基于ES4的后续工作称为ECMAScript Harmony。接下来,为了解决“互联网开发需要更新的、标准化的JavaScript语言”这一迫切问题,不久它们就发布了ECMAScript Ed5这一版本,即ES5。JavaScript的发展历程如图1-6所示。

图1-6 JavaScript在语言特性上的历史以及ES5之后的方向

严格地说,ES5与ES4基本没有什么关系,而是对ES3.1所代表的语言方向的一个补充。换言之,ES5没有改变JavaScript 1.x的语言特性,而ES4则是一门集语言生产商所有创想之大成且又与JavaScript 1.x倡导的语言风格相去甚远的语言。历史证明,我们暂时抛弃了后者—过去10年,我们都未能将JavaScript 1.x推进到v2.0版本。

由于ES5秉承了JavaScript设计的原始思想,因此基于ES5又展开了新一轮的语言进化的角力(图1-6中的三条虚线试图说明,语言最初的特性设计是这一切的根源):

■ 第一个方向由Microsoft、Adobe等大厂商所主导,沿着ES4—或称为JS2、或ECMAScript Harmony—的方向,向更加丰富的面向对象(OO++)特性发展,主要试图解决大型系统开发中所需要的复杂的对象层次结构、类库以及框架。

■ 第二个方向,则由包括Brendan Eich本人在内的语言开发者、研究者主导,他们力图增强JavaScript语言的函数式特性(Functional++),因为这样的语言特性在解决许多问题时来得比结构化的、面向对象的语言更优雅有效,而且从语言角度看来,函数式更为“纯粹”。

■ 在第三个方向上,Common JS等开发组意识到JS1.x在应用于浏览器之外的开发场景中,以及在组织大型项目方面显得无力。而将这一问题归结起来,就是“缺乏基础运行框架和运行库”,于是通过参考传统的、大型的、系统级的应用开发语言,尝试性地提出了在JavaScript中的同等解决方案(System++)。

具体的引擎或框架已经不再是被关注的话题。ES4的失败给整个JavaScript领域带来的思考是:我们究竟需要一种怎样的语言?