JavaScript语言精髓与编程实践(第2版)

JavaScript语言精髓与编程实践(2

周爱民 

ISBN 978-7-121-15640-3

20123月出版

定价:79

16

476

宣传语:JavaScript视角看整个计算机语言的世界,小角度引来的大话题

本书详细讲述JavaScript 作为一种混合式语言的各方面特性,包括过程式、面向对象、函数式和动态语言特性等,在动态函数式语言特性方面有着尤为细致的讲述。本书的主要努力之一,就是分解出这些语言原子,并重现将它们混合在一起的过程与方法。通过从复杂性到单一语言特性的还原过程,读者可了解到语言的本质,以及层出不穷的语言特性背后的真相。

本书主要的著述目的是基于一种形式上简单的语言来讲述语言的本质及其应用。本书详细讲述了通过框架执行过程来构造一个JavaScript 扩展框架的方法,并完整地讲述了框架扩展中各种设计取舍,因此可以作为研究计算机程序设计语言时的参考,用以展示现实系统如何实现经典理论中的各种编程范型。

作者简介

周爱民(Aimingoo),国内软件开发界资深软件工程师、架构师,技术作家。有十余年的软件开发、项目管理、团队建设的经验。著有《Delphi源代码分析》、《大道至简》和《JavaScript语言精髓与编程实践》等专著。

2001年,主持完成的极光数据处理仓库中心系统被河南省信息产业厅授予省高新技术产品二等奖。

2003年,被美国Borland公司授予 “Borland Delphi产品专家称号。

2004年,出版《Delphi源代码分析》,被誉为“Delphi领域精品著作

2005年,发布《大道至简》电子版(第一版)。

2006年,发起开源项目QomolangmaOpenProiect,探讨语言系统基础技术。

20073月,出版《大道至简》(第二版)。

20083月,出版《JavaScript语言精髓与编程实践》第一版。

2 代序

要有光

《世界需要一种什么样的语言》节选

什么才是决定语言的未来的思想呢?或者我们也可以换个角度来提出这个问题:世

界需要一种什么样的语言?

特性众多、适应性强,就是将来语言的特点吗?我们知道现在的C#Java 都在这条道路上前进。与特定的系统相关,就是语言的出路吗?例如曾经的VC++,以及它面向不同平台的版本。当然,与此类似的语言,还有C,以及汇编语言等。

这些例举其实都是在特定环境下的特定语言,所不同的无非是此处的环境的大小。这其实也是程序员的心病:我们到底选Windows 平台,还是Java 平台,或者Linux 系统,再或者是……我们总是在不同的厂商及其支持的平台中选择,而最终这种选择又决定了我们所使用的语言。这与喜好无关,也与语言的好坏无关,不过是一种趋利的选择罢了。所以你在使用着的也许只是一种并不那么’”,以及并不能令你那么开心地编程的语言。你越发辛勤地工作,越发地为这些语言摇旗鼓噪,你也就离语言的真相越来越远。

当然,这不过是一种假设。但是,真相不都是从假设开始的吗?

语言有些很纯粹,有些则以混杂著称。如果编程世界只有一种语言,无论它何等复杂,也必因毫无比较而显得足够纯粹。所以只有在多种语言之间比较,才会有纯粹或混杂的差异:纯粹与混杂总是以一种或多种分类法为背景来描述的。

因此我们了解这些类属概念的标准、原则,也就回溯到了种种语言的本质:它是什么、怎么样,以及如何工作。这本书,将这些分类回溯到两种极端的对立:命令式与说明式、动态与静态。我讲述除了静态语言(一般是指类似CC++Delphi 等的强类型、静态、编译型语言)之外的其他三种类型。正是从根底里具有这三种类型的特性,所以JavaScript 具有令人相当困扰的混合语言特性。分离它们,并揭示将它们混沌一物的方法与过程,如历经涅磐。在这一经历中,这本书就是我的所得。

多年以来,我在我所看不见的黑暗与看得见的梦境中追寻着答案。这本书是我最终的结论,或者结论面前的最后一层表象:我们需要从纯化的语言中领悟到编程的本质,并以混杂的语言来创造我们的世界。我看到:局部的、纯化的语言可能带来独特的性质,而从全局来看,世界是因为混杂而变得有声有色。如果上帝不说要有光,那么我们将不能了解世象之表;而世象有了表面,便有了混杂的色彩,我们便看不见光之外的一切事物。我们依赖于光明,而事实是光明遮住了黑暗。如同你现在正在使用的那一种、两种或更多种语言,阻碍了你看到你的未来。

周爱民

2009 1 月于本书精简版序

1 代序

学两种语言

《我的程序语言实践》节选

《程序设计语言——实践之路》一书对语言有一个分类法,将语言分类为说明式命令式两种。Delphi 以及CC++JavaC#等都被分在命令式语言范型的范畴,函数式语言则是说明式范型中的一种。如今我回顾自己对语言的学习,其实十年也就学会了两种语言:一种是命令式的Pascal/Delphi,另一种则是说明式的JavaScript。当然,从语言的实现方式来看,一种是静态的,一种是动态的。

这便是我程序员生涯的全部了。

我毕竟不是计算机科学的研究者,而只是其应用的实践者,因此我从一开始就缺乏对程序的某些科学的或学术层面上的认识是很正常的。也许有些人一开始就认识到程序便是如此,或者一种语言就应当是这样构成和实现的,那么他可能是从计算机科学走向应用,故而比我了解得多些。而我,大概在十年前学习编程以及在后来很多年的实践中,仅被要求写出代码而从未被要求了解什么是语言。所以我才会后知后觉,才会在很长的时间里迷失于那些精细的、沟壑纵横的语言表面而不自知。然而一如我现在所见到的,与我曾相同地行进于那些沟壑的朋友,仍然在持续地迷惑着、盲目着,全然无觉于沟壑之外的瑰丽与宏伟。

前些天写过一篇博客,是推荐那篇十年学会编程的。那篇文章道出了我在十年编程实践之后,对程序语言的最深刻的感悟。我们学习语言其实不必太多,深入一两种就可以了。如果在一种类型的语言上翻来覆去,例如不断地学CDelphiJavaC#……无非是求生存、讨生活,或者用以装点个人简历,于编程能力的提高用处是不大的。更多的人,因为面临太多的语言选择而浅尝辄止,多年之后仍远离程序根本,成为书写代码的机器,把书写代码的行数、程序个数或编程年限作为简历中最显要的成果。这在明眼人看来,不过是熟练的砌砖工而已。

我在《大道至简》中说如今我已经不再专注于语言。其实在说完这句话之后,我就已经开始了对JavaScript 的深入研究。在如此深入地研究一种语言,进而与另一种全然有别的语言比较之后,我对程序=算法+结构有了更深刻的理解与认识。尽管这句名言从来未因我的认识而变化过,从来未因说明与命令的编程方式而变化过,也从来未因动态与静态的实现方法而变化过。

动静之间,不变的是本质。我之所以写这篇文章,并非想说明这种本质是什么抑或如何得到,只是期望读者能在匆忙的行走中,时而停下脚步,远远地观望一下目标罢了。而我此刻,正在做一个驻足观望的路人。

周爱民

2007 11 月于个人博客

语言

语言是一种交流的工具,这约定了语言的工具本质,以及交流的功用。工具的选择只在于功用是否能达到,而不在于工具是什么。

在数千年之前,远古祭师手中的神杖就是他们与神交流的工具。祭师让世人相信他们敬畏的是神,而世人只需要相信那柄神杖。于是,假如祭师不小心丢掉了神杖,就可以堂而皇之地再做一根。甚至,他们可以随时将旧的换成更新或更旧的神杖,只要他们宣称这是一根更有利于通神的杖。对此,世人往往做出迷惑的表情,或者呈现欢欣鼓舞的情状。今天,这种表情或情状一样地出现在大多数程序员的脸上,出现在他们听闻到新计算机语言被创生的时刻。

神杖换了,祭师还是祭师,世人还是会把头叩得山响。祭师掌握了与神交流的方法(如果真如同他们自己说的那样),而世人只看见了神杖。

所以,泛义的工具是文明的基础,而确指的工具却是愚人的器物。

计算机语言有很多种分类方法,例如高级语言或者低级语言。其中一种分类方法,就是将计算机语言分为静态语言动态语言”——事物就是如此,如果用一对绝对反义的词来分类,就相当于涵盖了事物的全体。当然,按照中国人中庸平和的观点,以及保守人士对未知可能性的假设,我们还可以设定一种中间态:半动态语言。你当然也可以叫它半静态语言。

所以,我们现在是在讨论一种很泛义的计算机语言工具。至少在眼下,它(在分类概念中)涵盖了计算机语言的二分之一。当然,限于我自身的能力,我只能讨论一种确指的工具,例如JavaScript。但我希望你由此看到的是计算机编程方法的基础,而不是某种愚人的器物。JavaScript 的生命力可能足够顽强,我假定它比C 语言还顽强,甚至比你我的生命都顽强。但它只是愚人的器物,因此反过来说:它能不能长久地存在并不重要,重要的是它能不能作为这二分之一的泛义来供我们讨论。

分类法

打开一副新扑克牌,我们总看到它被整齐地排在那里,从A K 及大小王。接下来,我们将它一分为二,然后交叉在一起;再分开,再交叉……但是在重新开局之前,你是否注意到:在上述过程中,牌局的复杂性其实不是由分开这个动作导致的,而是由交叉这个动作导致的。

所以分类法本身并不会导致复杂性。就如同一副新牌只有4 A~K,我们可以按13种牌面来分类,也可以按4 种花色来分类。当你从牌盒里把它们拿出来的时候,无论它们是以哪种方式分类的,这副牌都不混乱。混乱的起因,在于你交叉了这些分类。

同样的道理,如果世界上只有动态、静态两种语言,或者真有半动态语言而你又有明确的分类法,那么开发人员将会迎来清醒、明朗的每一天:我们再也不需要花更多的时间去学习更多的古怪语言了。

然而,第一个问题便来自于分类本身。因为非此即彼的分类必然导致特性的缺失——如果没有这样非此即彼的标准就不可能形成分类,但特性的缺失又正是开发人员所不能容忍的。

我们一方面吃着碗里的,一方面念着锅里的。即使锅里漂起来的那片菜叶未见得有碗里的肉好吃,我们也一定要捞起来尝尝。而且大多数时候,由于我们吃肉吃腻了嘴,因此会觉得那片菜叶味道更好。所以,是我们的个性决定了我们做不成绝对的素食者或肉食者。

当然,更有一些人说我们的确需要一个新的东西来使我们更加强健。但不幸的是,大多数提出这种需求的人,都在寻求纯质银弹或混合毒剂。无论如何,他们要么相信总有一种事物是完美武器,要么相信更多的特性放在一起就变成了魔力的来源。

我不偏向两种方法之任一。但是我显然看到了这样的结果,前者是我们在不断地创造并特化某种特性,后者是我们在不断地混合种种特性。

更进一步地说,前者在产生新的分类法以试图让武器变得完美,后者则通过混淆不同的分类法,以期望通过突变而产生奇迹。二者相同之处,在于都需要更多的分类法。

函数式语言就是来源于另外的一种分类法。不过要说明的是,这种分类法是计算机语言的原理之一。基本上来说,这种分类法在电子计算机的实体出现以前就已经诞生了。这种分类法的基础是运算产生结果,还是运算影响结果。前一种思想产生了函数式语言(如LISP)所在的说明式语言这一分类,后者则产生了我们现在常见的CC++等语言所在的命令式语言这一分类。

然而我们已经说过,人们需要更多的分类的目的,是要么找到类似银弹的完美武器,要么找到混合毒剂。所以一方面很多人宣称函数式是语言的未来,另一方面也有很多人把这种分类法与其他分类法混在一起,于是变成了我们这本书所要讲述的动态函数式语言。毋庸置疑的是:还会有更多的混合法产生。因为保罗· 格雷厄姆(PaulGraham)已经做过这样的总结:二十年来,开发新编程语言的一个流行的秘诀是:取C 语言的计算模式,逐渐地往上加LISP 模式的特性,例如运行时类型和无用单元收集。

然而,这毕竟只是创生一种新语言的魔法。那么,到底有没有让我们在这浩如烟海的语言家族中,找到学习方法的魔法呢?

我的答案是:看清语言的本质,而不是试图学会一门语言。当然,这看起来非常概念化。甚至有人说我可能是从某本教材中抄来的,另外一些人又说我试图在这本书里宣讲类似于我那本《大道至简》里的老庄学说。

其实这很冤枉。我想表达的意思不过是:如果你想把一副牌理顺,最好的法子,是回到它的分类法上,要么从A K 整理,要么按4 个花色整理。毕竟,两种或更多种分类法作用于同一事物,只会使事物混淆而不是弄得更清楚。

因此,本书从语言特性出发,把动态与静态、函数式与非函数式的语言特性分列出来。先讲述每种特性,然后再讨论如何去使用(例如交叉)它们。

特性

无论哪种语言(或其他工具)都有其独特的特性,以及借鉴自其他语言的特性。有些语言通体没有独特特性,只是另外一种语言的副本,这更多的时候是为了满足一些人使用语言的习惯。还有一些语言则基本上全是独特的特性,这可能导致语言本身不实用,但却是其他语言的思想库。

我们已经讨论过这一切的来源。

对于 JavaScript 来说,除了动态语言的基本特性之外,它还有着与其创生时代背景密切相关的一些语言特性。直到昨天,JavaScript 的创建者还在小心翼翼地增补着它的语言特性。JavaScript 轻量的、简洁的、直指语言本质的特性集设计,使它成为解剖动态语言的有效工具。这个特性集包括:

一套参考过程式语言惯例的语法。

一套以原型继承为基础的对象系统。

一套支持自动转换的弱类型系统。

动态语言与函数式语言的基本特性。

需要强调的是,JavaScript 1.x 非常苛刻地保证这些特性是相应语言领域中的最小特性集(或称之为语言原子),这些特性在JavaScript 中相互混合,通过交错与补充而构成了丰富的、属于JavaScript 自身的语言特性。

本书的主要目的之一,就是分解出这些语言原子,并探究重新将它们混合在一起的过程与方法。通过从复杂性到单一语言特性的还原过程,让读者了解到语言的本质,以及层出不穷的语言特性背后的真相。

技巧

技巧是技术的取巧之处,所以根本上来说,技巧也是技术的一部分。很多人(也包括我)反对技巧的使用,是因为难以控制,并且容易破坏代码的可读性。

哪种情况下代码是需要易于控制可读性强呢?通常,我们认为在较大型的工程下需要更好地控制代码;在更多人共同开发的项目代码上要求更好的可读性。然而,反过来说,在一些更小型的、不需要更多人参与的项目中,适度地使用技巧是否就可以接受呢?

这取决于需要、能够维护这个代码的人对技巧的理解。这包括:

技巧是一种语言特性,还是仅特定版本所支持或根本就是BUG

技巧是不是唯一可行的选择,有没有不需要技巧的实现?

技巧是为了实现功能,还是为了表现技巧而出现在代码中的?

即使知晓问题的答案,我仍然希望每一个技巧的使用都有说明,甚至示例。如果维护代码的人不能理解该技巧,那么连代码本身都失去了价值,更何论技巧存在于这份代码中的意义呢?

所以,虽然本书中的例子的确要用到许多技巧,但我一方面希望读者能明白,这是语言内核或框架内核实现过程中必需的,另一方面也希望读者能从这些技巧中学习到它原本的技术和理论,以及活用的方法。

然而对于很多人来说,本书在讲述一个完全不同的语言类型。在这种类型的语言中,本书所讲述的一切,都只不过是正常的方法;在其他类型的一些语言中,这些方法看起来就成了技巧。例如,在JavaScript 中要改变一个对象方法指向的代码非常容易,并且是语言本身赋予的能力;而在Delphi/C++中,却成了破坏面向对象设计的非正常手段。

所以你最好能换一个角度来看待本书中讲述的方法。无论它对你产生多大的冲击,你应该先想到的是这些方法的价值,而不是它对于你所认为的传统的挑战。事实上,这些方法,在另一些同样传统的语言类型中,已经存在了足够长的时间——如同方法之于对象一样,原本就是那样(至少看起来)自然而然地存在于它所在的语言体系之中。

语言特性的价值依赖于环境而得以彰显。横行的螃蟹看起来古怪,但据说那是为了适应一次地磁反转。螃蟹的成功在于适应了一次反转,失败(我们是说导致它这样难看)之处,也在于未能又一次反转回来。

这本书

你当然可以置疑:为什么要有这样的一本书?是的,这的确是一个很好的问题。

首先,这本书并不讲 Web 浏览器(Web Browser,例如Internet Explorer)。这可能令人沮丧,但的确如此。尽管在很多人看来,JavaScript 就是为浏览器而准备的一种轻量的语言,并认为它离开了DOMHTMLCSS 就没有意义。在同样的看法之下,国内外的书籍在谈及JavaScript 时,大多会从如何在Web 页面上验证一个输入框值的有效性讲起。

是的,最初我也是这样认为的。因为本书原来就是出自我在写《B 端开发》一书的过程之中。《B 端开发》是一本讲述在浏览器(Browser)上如何用JavaScript 开发的书。然而,《B 端开发》写到近百页就放下了,因为我觉得应该写一本专门讲JavaScript的书,这更重要。

所以,现在你将要看到的这本书就与浏览器无关。在本书中我会把JavaScript 提升到与JavaC#Delphi 一样的高度,来讲述它的语言实现与扩展。作为实践,本书还在最后一部分内容中,借助名为“QoBean”的元语言框架讨论了语言扩展的方法7。但是,总的来说,本书不讲浏览器,不讲Web,也并不讲通常概念下的”AJAX

JavaScript 是一门语言,有思想的、有内涵的、有灵魂的语言。如果你没意识到这一点,那么你可能永远都只能拿它来做那个验证一个输入框值的有效性的代码。本书讲述JavaScript 的这些思想、核心、灵魂,以及如何去丰富它的血肉。最为核心的内容是在第2 章至第6 章,包括:

以命令式为主的一般化的JavaScript 语言特性,以及其对象系统。

动态、函数式语言,以及其他语言特性在JavaScript 中的表现与应用。

使用动态函数式特性来扩展JavaScript 的特性与框架。

在撰述这些内容的整个过程中,我一直在试图给这本书找到一个适合的读者群体,但我发现很难。因为通常的定义是低级、中级与高级,然而不同的用户对自己的等级的定义标准并不一样。在这其中,有十年学会编程的谦谨者,也有三天学会某某语言的速成家。所以,我认为这样定位读者的方式是徒劳的。

如果你想知道自己是否适合读这本书,建议你先看一下目录,然后试读一些章节。你可以先选读一些在你的知识库中看来很新鲜的,以及一些你原本已经非常了解的内容。通过对比,你应该知道这本书会给你带来什么。

不过我需要强调一些东西。这本书不是一本让你学会某某语言的书,也不是一本让初学者学会编程的书。阅读本书,你至少应该有一点编程经验(例如半年至一年),而且要摈弃某些偏见(例如C 语言天下无敌或JavaScript 是新手玩具)。

最后,你至少要有一点耐心与时间。

posted @ 2012-05-04 10:18  博文视点(北京)官方博客  阅读(549)  评论(0编辑  收藏  举报