第 1 章 JavaScript概要

第 1 章 JavaScript 概要

本章将介绍 JavaScript 和 ECMAScript 的关系与历史,以及 JavaScript 与作为其实现方式和运行环境的浏览器的关系,此外还将总括 JavaScript 的可移植性。

1.1 JavaScript 概要

我们首先介绍 JavaScript 相关的运行环境,其语言特征会在第 2 部分详述。正在读本书的读者,应该都知道 JavaScript 是在浏览器中运行的语言吧。甚至可以说,除开发者以外,被大众所熟知的程序设计语言也许只有 JavaScript。而且在软件史上,以能够在各种环境下运行而著称的语言中,大概没有比 JavaScript 更有名的了。

但是,正是由于太过常见,才让很多人对 JavaScript 有了一些误解与偏见。

例如,因为和浏览器的关联性过强,很多人都以为 JavaScript 只能在浏览器中运行。对 JavaScript 的看法也是莫衷一是。有人认为它降低了 Web 的使用体验,也有人称赞它是一门使 Web 的易用性得以进化的出色的技术。有人觉得 JavaScript 是任何人都可以学会的简单语言,也有人认为它过于抽象,很难掌握。

对 JavaScript 的看法各有不同,很难说哪一种正确。不过,只要软件以 Web 为中心,今后 JavaScript 的重要性就一定会进一步提升。JavaScript 领域的名人道格拉斯 • 克罗克福德曾把 JavaScript 称为 Web 上 的虚拟机。其核心含义是,在 JavaScript 广为普及的现在,Web 已经成为了 JavaScript 事实上的运行环境。夸张地讲,JavaScript 正日益成为支配世界的程序设计语言。

虽说 JavaScript 已被逐渐应用于浏览器之外的场合,但就目前而言,其主战场还是浏览器。本书除第 6 部分之外,原则上将 JavaScript 作为在浏览器中运行的客户端语言。

1.2 JavaScript 的历史

JavaScript 于 1995 年登场,运用在当时最流行的浏览器 Netscape Navigator 中。在此之前,浏览器只能处理 HTML 与图片,而 JavaScript 使得浏览器端的程序运行成为可能。

能够在浏览器中运行程序,并非 JavaScript 的专利。其先驱是另一门著名的程序设计语言 Java,主要用于服务器端。当初被称为 Java Applet 的程序由于可以在浏览器(HotJava)中运行而广受瞩目。

众所周知,尽管 Java 和 JavaScript 在保留字和关键字等表层范畴上很相似,但作为程序设计语言,它们之间其实并没有什么关系。JavaScript 开发得较晚,开发之初的名称是 LiveScript,之后才决定效仿已经颇为有名的 Java,改为 JavaScript。虽然 Java 和 JavaScript 的命名导致了许多误解,但回顾历史,可以说这是一种正确的营销手段。

稍微了解一下语言规则就会发现,Java 和 JavaScript 的执行方式并不像其表面那样相似。JavaScript 反而和 Ruby 或 Python 这样的轻型脚本语言,或 Lisp 之类的以函数作为主体的程序设计语言更为相似。不过由于早期主要是跟随 Java 发展,因此 JavaScript 的对象名以及方法名和 Java 比较相似。

JavaScript 简史

在此,我们总结一下 JavaScript 标准的制定时间和一些重要事件(表 1.1)。ECMAScript 将在下一节 中进行说明。

表 1.1 JavaScript 简史

年份

事件

1995 年

网景公司开发了 JavaScript

1996 年

微软发布了和 JavaScript 兼容的 JScript

1997 年

ECMAScript 第 1 版(ECMA-262)

1998 年

ECMAScript 第 2 版

1998 年

DOM Level1 的制定

1998 年

新型语言 DHTML 登场

1999 年

ECMAScript 第 3 版

2000 年

DOM Level2 的制定

2002 年

ISO/ IEC 16262:2002 的确立

2004 年

DOM Level3 的制定

2005 年

新型语言 AJAX 登场

2009 年

ECMAScript 第 5 版

2009 年

新型语言 HTML5 登场

最初,JavaScript 所获得的评价并不都是正面的。当时的 PC 性能很弱,JavaScript 的实现也不够成熟,很多人觉得运行了 JavaScript 的页面会变得十分缓慢,浏览器也会变得不稳定。甚至曾经有不少人大力呼吁,应该在浏览器中取消 JavaScript。

随着 Web 使用的普及,要求改善浏览器用户界面的呼声越来越高。因此尽管速度不快,JavaScript 的重要性还是在逐步提升。在这段时期,网景公司以及微软都在不断地进行技术革新,微软逐渐取得技术上的领先地位。由微软等公司提出的 DHTML(动态 HTML)是 JavaScript 的基础。DHTML 是一种为了推广而命名的方便说法,意指 DOM 和 CSS 等 W3C 标准与 JavaScript 相结合后,所能提供的丰富的浏览器用户界面。

就这样,在 2000 年前后,JavaScript 相关的各种技术基本准备就绪。2005 年前后,Web 应用得到广泛普及。特别是出现了以谷歌为首提出的异步 JavaScript(之后统称为 AJAX,即 Asynchronous JavaScript and XML),使接近桌面应用的复杂用户界面得以实现。

在 Web 应用变得越来越复杂的过程中,JavaScript 的代码规模与复杂性也日益提升,prototype.js、jQuery 等各种 JavaScript 库相应登场。可以说,2005 年之后的几年是 JavaScript 的繁荣期。

在这一繁荣期中,还有另一个不能忽视的成员,即 Mozilla 基金会(Mozilla Foundation)。Mozilla 基金会的历史可以追随到网景公司时期。Mozilla 的发展历程不在本书的讲解范畴之内,在此略去,但是 Mozilla 的开源浏览器 Firefox 的坚实发展所带来的 JavaScript 的速度改善,确实是 JavaScript 繁荣的一大主要原因。说到 JavaScript 的性能提升,谷歌在 2008 年与浏览器 Google Chrome 一同发布的 JavaScript 引擎 v8 也是一个重要的契机。在此之后,发生了各种 JavaScript 实现方式之间比拼速度的状况。

1.3 ECMAScript

1.3.1 JavaScript 的标准化

上节提到,JavaScript 是由网景公司提出的。之后,微软开发了和 JavaScript 相兼容的 JScript 并将其应用于 Internet Explorer 中。不过,人们通常将两者统称为 JavaScript。

为了防止因两家公司独自开发而导致 JavaScript 分裂以及其他一些问题,网景公司提出了名为 Ecma International 的 JavaScript 标准化组织。这一标准语言的名称就是 ECMAScript。由于将语言规则的制定权交给了中立的标准化组织,网景公司放弃了对 JavaScript 的垄断地位,JavaScript 因此具备了标准化程序设计语言所必须的安定感。对于开发者来说,标准的程序设计语言不会随特定企业的想法而轻易改变,也更令人安心。这是因为如果一种语言由某一企业所控制,可能会发生开发终止或是需要收费使用的情况。

ECMAScript 的标准编号是 ECMA-262,并在之后获得了 ISO 的承认(ISO-16262)。通俗来讲,就是得到了 ISO 的权威认证。根据 ECMAScript 标准,网景公司的 JavaScript 被重新定义为一种符合 ECMAScript 标准的程序设计语言。微软的 JScript 亦然。即使之后 JavaScript 的开发主体由网景公司变为了 Mozilla 基金会,这一定义也没有改变。

之后还出现了其他 ECMAScript 的具体实现,不过现在都将它们统称为 JavaScript 实现。严格来说,由网景公司开发、现由 Mozilla 基金会继续发展的语言称为 JavaScript,其他 ECMAScript 标准的实现方式称为 JavaScript 的兼容实现方式。不过这样区分的意义并不大,所以本书将这些统称为 JavaScript 实现方式。目前,具代表性的 JavaScript 实现方式一方面以标准为主,一方面也在独立发展。也就是说,它们在提供了 ECMAScript 功能的基础上,继续提供其他便捷功能。事实上,JavaScript 的具体实现大部分都是 ECMAScript 的超集。因此,如果要保证可移植性,只要做到在代码中仅使用 ECMAScript 标准所包含的功能即可。

1.3.2 被放弃的 ECMAScript 第 4 版

表 1.1(JavaScript 简史)中并没有 ECMAScript 第 4 版,这是因为 ECMAScript 第 4 版没能符合要求而最终被放弃了。

ECMAScript 第 3 版是在 1999 年提出的。一方面可以说 JavaScript 在 10 年间保持了稳定不变,但另一方面也意味着它的标准止于 10 年之前,已经停止了前进。一般来说,1999 以后的 ECMAScript 第 3 版以及 JavaScript 1.5 版被作为默认标准,即使 JavaScript 增加了新功能也被视为增强功能。官方的意见是为了与标准相兼容,不应该使用新功能。标准化有积极的一面,但同时又由于其发展过于缓慢,导致了 JavaScript 的具体实现往往增加了很多独有功能,造成了代码可移植性降低的不良后果。

在大约 10 年的时间里(1999 年至 2008 年),ECMAScript 第 4 版的制定工作一直在进行,原本计划向业已规范有序的标准中进一步加入大量增强功能。在第 4 版中甚至有引入“类”的概念这样大胆的标准变更计划。然而,2008 年的标准化工作大会放弃了大幅度变更标准的计划,转为在第 3 版的基础上进行渐进式改进。于是,在 2009 年直接发布了和第 3 版标准差异不大的第 5 版。

由于 ECMAScript 第 5 版的保守,JavaScript 1.6 版中很多新增功能的处境也变得微妙起来。虽然其中也有一些功能仍然被 ECMAScript 第 5 版采用,但其大部分都没能被接受。因此,虽说只要遵循 ECMAScript 标准依然可以随意使用,但 JavaScript 1.6 版实际上成为了一种独立的 JavaScript 增强版本。总之,如果要遵循标准或是保证可移植性的话,就不应该使用那些功能。

1.4 JavaScript 的版本

正如上一节所讲,JavaScript 是一种符合 ECMAScript 标准的程序设计语言。而事实上,往往是先由 JavaScript 实现某一功能,ECMAScript 才对其进行标准化处理。由于历史原因,Mozilla 基金会所开发的 JavaScript(严格意义上的真正的 JavaScript)常常会在标准化之前就加入一些新功能。

JavaScript 版本和 ECMAScript 版本的对应关系如表 1.2 所示。

表 1.2 JavaScript 的版本

JavaScript 版本

最早采用该版本的浏览器版本

ECMAScript 标准

1.0

Navigator 2.0

-

1.1

Navigator 3.0

以此为基础开始了 ECMAScript 的标准化

1.2

Navigator 4.0-4.05

大致相当于第 1 版标准

1.3

Navigator 4.06-4.7x

第 1 版标准

1.4

-

第 1 版标准

1.5

Navigator 6.0,Mozilla

第 3 版标准

1.6

Firefox 1.5

相当于 ECMAScript 第 4 版的先行版

1.7

Firefox 2

相当于 ECMAScript 第 4 版的先行版

1.8

Firefox 3

相当于 ECMAScript 第 4 版的先行

1.8.1

Firefox 3.5

大致相当于第 5 版标准

1.8.5

Firefox 4.0

第 5 版标准

1.5 JavaScript 实现方式

表 1.3 列出了搭载了 JavaScript 引擎的具有代表性的浏览器。虽说这几年给每个版本附上一个开发代号的做法很流行,不过在这里还是使用各自的通称。

表 1.3 浏览器和 JavaScript 实现方式

浏览器

JavaScript 实现方式

FireFox

SpiderMonkey

Internet Explorer

JScript

Safari

JavaScriptCore

Chrome

v8

Carakan

Carakan(最新版的开发代号)

客户端 JavaScript 代码的可移植性

JavaScript 编程中有一个很麻烦的问题,即在不同的浏览器中其执行方式会有所不同。1.2 节中曾提到 JavaScript 早期的评价并不太好,其中一个很重要的原因就是,JavaScript 在不同的浏览器中的执行方式的确会有差别。许多开发者怨声不断,逐渐造成了一种 JavaScript 编程非常麻烦的印象。但如果冷静下来思考一下,就会发现 JavaScript 其实并没有所说的那么夸张。

稍加了解就会发现,C/C++ 等其他一些语言,和如今的 JavaScript 一样,都衍生出了多种不同的实现方式 1。它们虽然在遵循语言标准时,能够实现一定程度的可移植性,但对于不同平台(OS)的情况,其可移植性完全无法令人满意。PHP、Perl、Python、Ruby 等流行的脚本语言虽然在不同平台间也有着很高的可移植性,但这是因为它们基本上只有唯一一种实现方式。Java 确实有多种实现方式,也实现了很强的可移植性,不过这是由于它最初就在保证可移植性上花费了很大的精力,所以算是一个例外。把 JavaScript 和 Java 作对比来得出其可移植性不强未免有些不妥。

1不过,C++ 的支持者们持有不同意见。由于本书只关注 JavaScript,所以对此不做深究。

影响客户端 JavaScript 可移植性的原因主要有两点。

  • JavaScript 语言实现方式的不同

  • 渲染引擎的差别(DOM 或是 CSS 的解释不同)

在实际中,后者更为麻烦,并由此产生了许多不良开发方式。要解决 JavaScript 语言实现方式差异的关键在于 ECMAScript,因为 ECMAScript 作为一种标准,有明确的规定。现在大多数有名的 JavaScript 实现都基于 ECMAScript 标准,所以只要书写符合 ECMAScript 标准的代码,就能够在很大程度上提高可移植性。

另一方面,渲染引擎没有像程序设计语言一样被标准化,所以相当难办。不过有一个被称为 Acid 的测试,可以用于减少这一不同引擎之间执行方式不同的问题。

http://www.webstardards.org/action/acid3/

Acid 并不像 ECMAScript 那样有明确标准,它会对浏览器进行特定测试,根据返回的结果是否相同来判断代码的执行情况。该测试可以用于判断 JavaScript、DOM、CSS 等各种客户端 JavaScript 的执行情况。现在很多的浏览器都以符合 Acid 标准(即可以通过 Acid 测试)为目标。在执笔本书时,Acid 的版本号为 3。用浏览器登录下面的 URL 地址就能够获得测试得分:

http://acid3.acidtests.org/

刚刚已经介绍了有关客户端 JavaScript 可移植性改进的内容。很可惜,情况尚不乐观。首先是浏览器版本陈旧的问题。之前提到的 ECMAScript 标准以及 Acid 测试标准都是基于最新版本的浏览器的。如果需要支持旧版本的浏览器,则仍然要注意执行方式上的差异。

另一个问题是对 PC 之外的设备的支持。如今的智能手机、平板电脑以及智能电视,原本就有着不同的用户界面。虽说客户端 JavaScript 的可移植性确实在逐渐提高,但如果考虑到现在越来越普及的非 PC 设备的情况,可以说现在正处于一种过去未曾有过的混乱状态。所幸非 PC 设备的渲染引擎基本上被 WebKit 所垄断,总算使问题稍有缓解。

1.6 JavaScript 运行环境

1.6.1 核心语言

由于人们对 JavaScript 的印象大多都是客户端 JavaScript,所以常认为 JavaScript 编程和 DOM 编程是不可分割的。

简单说来,DOM 编程就是浏览器和用户之间的接口,可以在浏览器上显示内容或是反馈用户的点击操作。本书第 3 部分将会对此做进一步详述。尽管在浏览器上两者的联系紧密,但 JavaScript 和 DOM 并不是不可分割的,它们的语言标准相互独立。DOM 对客户端 JavaScript 来说,仅仅是一宿主对象。大家对宿主对象一词可能并不熟悉,只要把它理解为类似于其他程序设计语言的外部库的概念即可,也就是语言中可以更换的部分。而核心语言则是特指 JavaScript 中不可被替代的功能。

JavaScript 的核心语言和宿主对象的概念如下图所示(图 1.1)。

{}

图 1.1 Web 应用程序的组成结构

1.6.2 宿主对象

如图 1.1 所示,JavaScript 中对于不同的运行环境,有着不同的内置宿主对象。这是由于 JavaScript 是被作为一种扩展语言而设计的。对于通用程序设计语言,开发者必须自己开发运行时的上下文环境。正因如此,那些语言才有了通用程序设计语言的名称。另一方面,扩展语言是在内建对象的应用程序(宿主环境)中运行程序的。宿主应用程序会在这时收到一些运行时的上下文信息。JavaScript 会以全局对象作为根节点的对象树的形式,接受这些上下文信息。在启动时,JavaScript 从宿主环境获取的对象树就被称为宿主对象。

从 JavaScript 代码的角度看来,全局对象在程序启动前就已经存在了。客户端 JavaScript 的全局对象被称作 window 对象。

1.7 JavaScript 相关环境

1.7.1 库

大约从 2005 年起,才正式开始使用开源的 JavaScript 库。首当其冲的是 prototype.js。虽然之前也有一些 JavaScript 库,不过直到从 prototype.js 开始,使用库才成为了一种常规做法。prototype.js 受到瞩目的理由之一是它支持多平台 AJAX 处理。

虽然这一时期 AJAX 正在逐步普及,但同时 AJAX 编程也存在重大问题。Internet Explorer 和 Firefox 这两个当时流行的浏览器的 API 并不兼容。而 prototype.js 提供的 API 则是弥合了两者 API 的不同,以解决这一问题。此外,它还提供了很多方便的 API,其中一些可以用于扩展 DOM 的功能,另一些则是 Ruby 迭代器的衍生。

在此之后,如表 1.4 所示,出现了大量的 JavaScript 库。

表 1.4 代表性的客户端 JavaScript 库

名称

发布URL

prototype.js

http://www.prototypejs.org/

script.aculo.us

http://script.aculo.us/

jQuery

http://jquery.com/

Ext.js

http://www.sencha.com/products/extjs/

Yahoo! UI Library(YUI)

http://developer.yahoo.com/yui/

Dojo

http://dojotoolkit.org/

MochiKit

http://mochi.github.com/mochikit/

MooTools

http://code.google.com/closure/libray/

uupaa.js

http://code.google.com/p/uupaa-js/

1.7.2 源代码压缩

为了使客户端 JavaScript 的执行更加高速,可以对源代码进行压缩。通过压缩源代码可以实现以下效果以提高执行速度。

  • 减少了网络通信传送量而使得网络等待时间减少。

  • 源代码缩短之后,JavaScript 解释器(浏览器)用于解释代码的时间减少。

  • (有些压缩工具可以使)源代码得到优化。

代表性的源代码压缩工具如表 1.5 所示。

表 1.5 源代码压缩工具

名称

URL

Google Closure Compiler

http://code.google.com/closure/compiler/

YUI Compressor

http://developer.yahoo.com/yui/compressor/

packer

http://dean.edwards.name/packer/

JSMin

http://www.crockford.com/javascript/jsmin.html

单纯的压缩工具的效果只是删除不需要的空白内容、换行符以及注释等。为了提高运行速度而不写必要的注释并不是可取的做法,所以,这样单纯的压缩工具也是有其存在意义的。稍高级一些的压缩工具则会进行将变量名替换为较短的字符串之类的处理,不过这样一来,源代码的可读性也会大大降低。更高级一些的压缩工具能够像大多数的编译器那样对代码进行优化。例如,去除无用的代码,或是预先计算代码中的一些表达式,并将其替换为常量,等等。而要实现这一效果,就不能把源代码仅看作是单纯的字符串,还要以 JavaScript 的标准正确地解释其含义。这样一来,也就实现了对代码的检查,能够发现代码中一些潜在的错误。

虽然对源代码进行压缩非常地麻烦,但相应的也能获得不小的收获。因而,在开发规模较大的情况下,应当对源代码进行压缩。

1.7.3 集成开发环境

JavaScript 已经有了不少的集成开发环境(IDE),不过其中的一些还尚未完善。代表性的 IDE 如表 1.6 所示。

表 1.6 JavaScript 的 IDE

名称

说明

Orion

Eclipse 基金会提供的基于Web 的JavaScript 专用IDE

Cloud9

云端在线(http://cloud9ide.com)JavaScript 专用IDE

Eclipse

Eclipse 基金会提供的IDE。作为Java IDE 而闻名,同时也支持JavaScript

NetBeans

由Oracle(原Sun)开发。作为Java IDE 而闻名,同时也支持JavaScript

Aptana Studio

Appcelerator(Titanium 的开发商)所收购的Aptana 公司(http://www.aptana.org)的免费产品

WebStorm

JetBrains 公司的收费产品(http://www.jetbrains.com/webstorm/

Komodo IDE

ActiveState 公司的收费产品

目录