图灵社区会员 StinkBC(StinkBC@gmail.com) 专享 尊重版权
图灵社区会员 StinkBC(StinkBC@gmail.com) 专享 尊重版权
内 容 提 要
本书是 JavaScript 超级畅销书的最新版。ECMAScript 5 和 HTML5 在标准之争中双双胜出,使大量
专有实现和客户端扩展正式进入规范,同时也为 JavaScript 增添了很多适应未来发展的新特性。本书这
一版除增加 5 章全新内容外,其他章节也有较大幅度的增补和修订,新内容篇幅约占三分之一。全书从
JavaScript 语言实现的各个组成部分——语言核心、DOM、BOM、事件模型讲起,深入浅出地探讨了面向
对象编程、Ajax 与 Comet 服务器端通信,HTML5 表单、媒体、Canvas(包括 WebGL)及 Web Workers、
地理定位、跨文档传递消息、客户端存储(包括 IndexedDB)等新 API,还介绍了离线应用和与维护、性
能、部署相关的最佳开发实践。本书附录展望了未来的 API 和 ECMAScript Harmony 规范。
本书适合有一定编程经验的 Web 应用开发人员阅读,也可作为高校及社会实用技术培训相关专业课
程的教材。
图灵程序设计丛书
JavaScript高级程序设计(第3版)
定价:99.00元
读者服务热线:(010)51095186转604 印装质量热线:(010)67129223
反盗版热线:(010)67171154
著 [美] Nicholas C. Zakas
译 李松峰 曹 力
责任编辑 朱 巍
人民邮电出版社出版发行 北京市崇文区夕照寺街14号
邮编 100061 电子邮件 315@ptpress.com.cn
网址 http://www.ptpress.com.cn
北京 印刷
开本:800×1000 1/16
印张:46.75 彩插:8
字数:1092千字 2012年3 月第1版
印数:1 — 6 000册 2012年3月北京第1次印刷
著作权合同登记号 图字:01-2012-1175 号
ISBN 978-7-115-27579-0
◆
◆
◆
图灵社区会员 StinkBC(StinkBC@gmail.com) 专享 尊重版权
错误!文档中没有指定样式的文字。 1
1
2
3
4
5
13
6
7
8
9
10
11
12
版 权 声 明
Original edition, entitled Professional JavaScript for Web Developers 3rd Edition, by Nicholas C. Zakas,
ISBN 978-1-118-02669-4, published by John Wiley & Sons, Inc.
Copyright ©2012 by John Wiley & Sons, Inc.,All rights reserved.This translation published under License.
Translation edition published by POSTS & TELECOM PRESS Copyright ©2012.
Copies of this book sold without a Wiley sticker on the cover are unauthorized and illegal.
本书简体中文版由 John Wiley & Sons, Inc.授权人民邮电出版社独家出版。
本书封底贴有 John Wiley & Sons, Inc.激光防伪标签,无标签者不得销售。
版权所有,侵权必究。
图灵社区会员 StinkBC(StinkBC@gmail.com) 专享 尊重版权
4 第 5 章 IDA 数据显示窗口
序
20 多年的职业生涯,我也长出了白头发。回首往事,曾经对我的职业道路产生过重要影响的技术和
人历历在目。如果让我只说一种技术,一种对我产生了最大正面影响的技术,那么就是 JavaScript。说
实话,我也并非一直都是 JavaScript 的信徒。跟许多人一样,我以前也把它当作一门玩具语言,认为它
只能用来做一些旋转的横幅广告,或者在页面中添加一些有意思的交互效果作为装饰。我原来是做服务
器端开发的,我们都对这种玩具语言不感冒,该死的!可是,后来 Ajax 出现了。
永远也忘不了当时无孔不入的 Ajax,大家都认为它是一种非常酷、非常新,同时极具创造性的技术。
我也开始了解它,阅读相关资料。知道这门曾被我嗤之以鼻的玩具语言如今被每一位专业 Web 开发人
员津津乐道之后,我感到很震惊。突然,我的看法就转变了。随着探索 Ajax 的继续深入,我认识到
JavaScript 的强大威力,急切地想了解它能提供的所有“法宝”。于是,我全身心地投入到学习 JavaScript
之中,不仅努力学习这门语言,还加入了 jQuery 项目团队,专门从事客户端开发。我的日子过得很爽。
对 JavaScript 了解得越深,接触的开发人员就越多,其中不乏今天在我眼里依然是巨星和导师级的
人物。尼古拉斯·泽卡斯(本书作者)就是这样一位开发人员。我一直记得在读本书第 2 版时心中油然
而生的喜悦之情,虽然我也有多年的积累,但仍然从中学到了很多新东西。这本书实实在在、深入浅出,
读来就好像尼古拉斯对不同层次的读者都了如指掌,所以他的风格才那么贴切自然。对于技术书来说,
这是非常突出的一个特色。多数作者都想靠坚深的技术给人留下印象,但这本书不同。所以,它很快就
成为了我案头必备的书,我也会向那些有志全面掌握 JavaScript 的开发人员推荐这本书。我希望每个人
对这本书都能有跟我一样的体会,认识到它的价值所在。
后来,在一次jQuery大会上,我荣幸地见到了尼古拉斯本人。站在我面前的是一位世界顶级的JavaScript
开发人员,而且正负责世界上最重要的一个 Web 站点(雅虎)。尼古拉斯是我见过的最随和的人之一。真
的,见到他的时候我有一种追星族的幻觉。但他就是那么一个活生生的人,一个想帮助开发人员成就梦想
的人。不仅他的书改变了我对 JavaScript 的认识,而且尼古拉斯这个人,也让我愿意接近,愿意了解。
听说尼古拉斯要请我作序,我激动得不知道说什么才好。在此,我代表大牛来为本书暖场。这个序
也是他本人有多么令人景仰的一个明证。不过,更重要的是,这也给了我一个机会,让我能跟大家分享
自己为什么觉得这本书如此重要。我看过很多 JavaScript 图书,的确也有很多令人叹服的佳作。但在我
看来,这本书为读者成为全方位的 JavaScript 高手提供了“一揽子方案”。
这本书从介绍表达式和变量声明开始,平滑地过渡到了闭包、面向对象开发等高级主题。与那些把
大量篇幅花在讲解背景知识上的书,以及那些让人感觉好像是要使用 JavaScript 开发导弹制导系统的书
相比,这本书让人感觉细致周到、亲切自然。这是一本写给“普通人”的书,它能让你编写出引以为荣
的代码,构建出令人叫绝的网站。
雷·邦戈(Rey Bango)
微软公司高级布道师,jQuery 项目团队核心成员
图灵社区会员 StinkBC(StinkBC@gmail.com) 专享 尊重版权
前 言 1
1
2
3
4
5
13
6
7
8
9
10
11
12
前 言
从驱动全球商业、贸易及管理领域不计其数的复杂应用程序的角度来看,说 JavaScript 已经成为当
今世界上最流行的编程语言一点儿都不为过。
JavaScript 是一种非常松散的面向对象语言,也是 Web 开发中极受欢迎的一门语言。JavaScript,尽
管它的语法和编程风格与 Java 都很相似,但它却不是 Java 的“轻量级”版本,甚至与 Java 没有任何关
系。JavaScript 是一种全新的动态语言,它植根于全球数亿网民都在使用的 Web 浏览器之中,致力于增
强网站和 Web 应用程序的交互性。
在本书中,我们将对 JavaScript 追根溯源,从它在最早的 Netscape 浏览器中诞生谈起,一直谈到今
天的它对 DOM 和 Ajax 的强大支持。读者将通过本书掌握如何运用和扩展这门语言,从而更好地满足自
己的需求,以及如何实现客户端与服务器的无缝通信,而又不必求助于 Java 或隐藏的网页框架(frame
元素)。一言以蔽之,本书将教会你在面对各种常见的 Web 开发问题时,如何拿出自己的 JavaScript 解
决方案。
本书读者对象
本书将下列三类人员作为目标读者:
(1) 熟悉面向对象编程、经验丰富而又打算学习 JavaScript 的开发人员,JavaScript 毕竟与 Java、C++
等传统 OO 语言存在着诸多联系;
(2) 有意提升自己网站和 Web 应用程序易用性的 Web 开发人员;
(3) 希望全面深入地理解这门语言的初级 JavaScript 开发人员。
此外,本书也适合熟悉下列相关技术的读者阅读:
(1) Java
(2) PHP
(3) ASP.NET
(4) HTML
(5) CSS
(6) XML
本书不适合没有计算机基础知识的初学者,也不适合只想为网站添加简单交互功能的读者。建议这
些朋友学习阅读 Beginning JavaScript, 3rd Edition(Wiley, 2007)一书①。
——————————
① 本书中文版《JavaScript 入门经典(第 3 版)》已经由清华大学出版社出版。——译者注(以下脚注如无特殊说明,
均为译者注)
献给我的父母,是他们永远给我支持和鼓励。
图灵社区会员 StinkBC(StinkBC@gmail.com) 专享 尊重版权
2 前 言
本书内容
本书提供了 JavaScript 开发人员必须掌握的内容,全面涵盖了 JavaScript 的各种高级、有用的特性。
本书首先介绍了 JavaScript 的起源及其发展现状,随后讨论了构成 JavaScript 实现的各个组成部分,
重点讲解了 ECMAScript 和 DOM 标准。此外,还对不同 Web 浏览器的 JavaScript 实现之间存在的差异,
给出了相应的说明。
在此基础上,本书从讲解 JavaScript 的基本概念入手,探讨了 JavaScript 面向对象程序设计和继承的
方式,以及如何在 HTML 等标记语言中使用它。在深入剖析了事件和事件处理之后,又解释了各种浏
览器检测技术。本书还探讨了 HTML5、Selectors API 和 File API 等一系列新 API。
本书最后一部分专门讨论了高级主题,涉及性能和内存优化、最佳实践以及对 JavaScript 未来的
展望。
本书结构
本书共 25 章,各章简介如下。
第 1 章“JavaScript 简介”,讲述了 JavaScript 的起源:因何而生,如何发展,现状如何。涉及的
概念主要有 JavaScript 与 ECMAScript 之间的关系、DOM(Document Object Model,文档对象模型)、
BOM(Browser Object Model,浏览器对象模型)。此外,还将讨论 ECMA(European Computer
Manufacturer’s Association,欧洲计算机制造商协会)和 W3C(World Wide Web Consortium,万维网联
盟)制定的一些相关标准。
第 2 章“在 HTML 中使用 JavaScript”,介绍了如何在 HTML 中使用 JavaScript 创建动态网页。
这一章不仅展示了在网页中嵌入 JavaScript 的各种方式,还讨论了 JavaScript 内容类型(content-type)及
其与<script>元素的关系。
第 3 章“基本概念”,讨论了 JavaScript 语言的基本概念,包括语法和流控制语句。这一章也分析
了 JavaScript 与其他基于 C 的语言在语法上的相同和不同之处,还介绍了与内置操作符有关的类型转换
问题。
第 4 章“变量、作用域和内存问题”,探讨了 JavaScript 如何处理其松散类型的变量。这一章还讨
论了原始值和引用值之间的差别,以及与变量有关的执行环境的相应内容。最后,通过介绍 JavaScript
的垃圾收集机制,解释了变量在退出作用域时释放其内存的问题。
第 5 章“引用类型”,详尽介绍了 JavaScript 内置的所有引用类型,如 Object 和 Array。这一
章对 ECMA-262 规范中描述的每一种引用类型既做了理论上的阐释,又从浏览器实现的角度给出了
介绍。
第 6 章“面向对象的程序设计”,讲述了在 JavaScript 中如何实现面向对象的程序设计。由于
JavaScript 没有类的概念,因此这一章从对象创建和继承的层面上展示了一些流行的技术。此外,这一
章还讲解了函数原型的概念,并对函数原型与整个面向对象方法的关系进行了探讨。
第 7 章“函数表达式”,集中介绍了 JavaScript 中最为强大的一个特性——函数表达式。相关的内
容涉及闭包、this 对象的角色、模块模式和创建私有对象成员等。
第 8 章“BOM”,介绍 BOM(Browser Object Model,浏览器对象模型),即负责处理与浏览器自
身有关的交互操作的对象集合。这一章全面介绍了每一个 BOM 对象,包括 window、document、
图灵社区会员 StinkBC(StinkBC@gmail.com) 专享 尊重版权
前 言 3
1
2
3
4
5
13
6
7
8
9
10
11
12
location、navigator 和 screen。
第 9 章“客户端检测”,讨论了检测客户端机器及其支持特性的各种手段,包括特性检测及用户代
理字符串检测的不同技术。这一章还就每种手段的优缺点及适用情形给出了详细说明。
第 10 章“DOM”,介绍 DOM(Document Object Model,文档对象模型),即 DOM1 规定的 JavaScript
中的 DOM 对象。这一章也简要介绍了 XML 及其与 DOM 的关系,为深入探讨所有 DOM 规范及其定义
的操作网页的方式奠定了基础。
第 11 章“DOM 扩展”,介绍了其他 API 以及浏览器本身为 DOM 添加的各种功能。涉及内容包括
Selectors API、Element Traversal API 和 HTML5 扩展。
第 12 章“DOM2 和 DOM3”,在前两章的基础上继续探讨了 DOM2 和 DOM3 中新增的 DOM 属
性、方法和对象。这一章还讨论了 IE 与其他浏览器的兼容性问题。
第 13 章“事件”,解释了 JavaScript 中事件的本质,对遗留机制的支持,以及 DOM 对事件机制的
重新定义。这一章讨论了多种设备,包括 Wii 和 iPhone。
第 14 章“表单脚本”,讲述如何使用 JavaScript 增强表单的交互性,突破浏览器的局限性。这一
章的讨论主要围绕单个表单元素如文本框、选择框,以及围绕数据验证和操作展开。
第 15 章“使用 Canvas 绘图”,讨论了<canvas>标签以及如何通过它来动态绘图。不仅涵盖 2D
上下文,也将讨论 WebGL(3D)上下文,可以为创建动画和游戏夯实基础。
第 16 章“HTML5 脚本编程”,介绍了 HTML5 规定的 JavaScript API,涉及跨文档传递消息、拖
放 API 和以编程方式控制<audio>和<video>元素,以及管理历史状态。
第 17 章“错误处理与调试”,讨论浏览器如何处理 JavaScript 代码错误,并展示了一些处理错误
的方式。这一章针对每种浏览器分别讨论了相应的调试工具和技术,还给出了简化调试工作的建议。
第 18 章“JavaScript 与 XML”,展示了 JavaScript 中用于读取和操作 XML(eXtensible Markup
Language,可扩展标记语言)的特性。这一章分析了不同浏览器提供的 XML 支持和对象的差异,给出
了编写跨浏览器代码的简易方法。此外,这一章还介绍了用于在客户端转换XML数据的XSLT(eXtensible
Stylesheet Language Transformations,可扩展样式表语言转换)技术。
第 19 章“E4X”,讨论了 E4X(ECMAScript for XML,ECMAScript 中的 XML 扩展);设计 E4X 的
出发点是简化 XML 处理任务。这一章探讨了在处理 XML 时,使用 E4X 与使用 DOM 相比有哪些
优势。
第 20 章“JSON”,介绍了作为 XML 替代格式的 JSON,包含浏览器原生支持的 JSON 解析和序
列化,以及使用 JSON 时要注意的安全问题。
第 21 章“Ajax 与 Comet”,讲解了常用的 Ajax 技术,包括使用 XMLHttpRequest 对象及 CORS
(Cross-Origin Resource Sharing,跨来源资源共享)API 实现跨域 Ajax 通信。这一章展示了浏览器在实
现与支持方面存在的差异,同时也给出了一些使用建议。
第 22 章“高级技巧”,深入讲解了一些 JavaScript 中较复杂的模式,包括函数柯里化(currying)、
部分函数应用和动态函数。这一章还讨论了如何创建自定义的事件框架和使用 ECMAScript 5 创建防篡
改对象。
第 23 章“离线应用与客户端存储”,讨论了如何检测应用离线以及在客户端机器中存储数据的各
种技术。先从受到最广泛支持的特性 cookie 谈起,继而介绍了新兴的客户端存储技术,如 Web Storage
和 IndexedDB。
图灵社区会员 StinkBC(StinkBC@gmail.com) 专享 尊重版权
4 前 言
第 24 章“最佳实践”,探讨了在企业级环境中使用 JavaScript 的各种方式。其中,着眼于提高可
维护性的内容包括编码技巧、格式化和通用编程实践。这一章还介绍了改善代码执行性能及速度优化的
一些技术。最后讨论了部署问题,包括如何创建构建过程。
第 25 章“新兴的 API”,介绍了为增强浏览器中的 JavaScript 而创建的新 API。虽然这些 API 还没
有得到完整或全面的支持,但它们已经崭露头角,有些浏览器也已经部分地实现了这些 API。这一章的
内容主要是 Web 计时和文件 API。
使用示例
要运行本书中的示例,需要安装下列软件:
Windows XP、Windows 7 或 Mac OS X;
Internet Explorer 6 及更高版本、Firefox 2 及更高版本、Opera 9 及更高的版本、Chrome、 Safari 2
及更高版本。
完整的示例源代码可以从 http://www.wrox.com/中下载(下载步骤见“源代码”一节)①。
排版约定
为了让读者更好地理解本书内容,同时把握住全书的重点,本书将采用以下排版约定。
这种带警告图标的方框样式,表示与上下文相关的重要的、需要牢记的内容。
这种带钢笔图标的方框样式,表示与上下文相关的说明、提示、技巧、窍门和背
景知识。
正文中的样式说明如下。
(1) 新术语及重要的词汇在首次出现时使用加粗字体以示强调;
(2) 表示键盘命令组合的方式是 Ctrl+A;
(3) 正文中的代码使用等宽字体,如 persistence.properties;
(4) 代码有两种样式:
var obj = new Object(); // 大多数示例代码都没有加粗
var obj = new Object(); // 加粗的代码表示在上下文中特别重要
源代码
在学习本书示例代码时,可以手工敲入所有代码,也可以使用随书的源代码文件。本书所有源代码
都可以到 www.wrox.com 中下载。登录该站点后,先找到本书(通过搜索或者图书列表),打开本书页
——————————
① 读者也可以在图灵社区(http://www.ituring.com.cn/)本书的页面中免费注册下载。
图灵社区会员 StinkBC(StinkBC@gmail.com) 专享 尊重版权
前 言 5
1
2
3
4
5
13
6
7
8
9
10
11
12
面后,单击其中的 Download Code 链接,就可以下载本书的源代码了①。对于包含在下载文件中的源代
码,书中会添加以下图标:
本书代码示例旁边会附有文件名,从中可以找到对应的代码片段。文件名的格式如下:
代码片段所在的文件名
由于很多书的书名看起来类似,所以更好的方式是通过书的 ISBN 来搜索它。本
书原版的 ISBN 是 978-1-118-02669-4。
下载完代码后,请使用解压缩软件将其解压缩。此外,读者也可以登录 Wrox 代码下载主页
www.wrox.com/dynamic/books/download.aspx,查找并下载本书及其他 Wrox 图书的示例代码。
勘误信息②
我们尽最大努力确保正文和代码没有错误。可是,金无足赤,错误在所难免。如果读者发现我们书
中的任何错误,例如错别字或代码片段无法运行等,希望您能及时给我们反馈。您提交的勘误不仅能让
其他读者受益,而且也能帮助我们进一步提高图书质量。
本书原版的勘误页面位于 www.wrox.com 中,登录该站点后可以通过搜索或查询图书列表找到本
书页面,然后单击页面中的 Errata(勘误)链接。然后可以看到其他读者已经提交并由 Wrox 的编辑发
布的勘误信息。另外,在 www.wrox.com/misc-pages/booklist.shtml 页面中也可以找到本书及勘误页面
的链接。
如果读者在本书勘误页面中没有发现“你的”错误,麻烦打开 www.wrox.com/contact/techsupport.shtml
页面,填写其中的表单并将错误发送给我们。我们会认真核对您提交的错误,如果错误确实存在,我们
将把它补充到本书勘误页面中。同时,也将根据您提供的信息对本书后续版本加以改正。
p2p.wrox.com
如果您想与本书作者或者其他读者沟通,请加入 P2P 论坛(p2p.wrox.com)。该论坛是基于 Web 的
系统,您可以在其中发表与 Wrox 图书及相关技术有关的帖子,并同其他读者或者技术用户交流。论坛
提供了一个订阅功能,您可以选择当发表您感兴趣的帖子时通过邮件通知您。Wrox 的作者、编辑、其
他行业的专家以及与您正在读同一本书的读者都会出现在这个论坛中。
在 http://p2p.wrox.com 中,有很多论坛不仅对您理解本书有帮助,而且还会对开发应用程序有帮助。
要加入这个论坛,请按下面几个步骤进行:
(1) 登录到 p2p.wrox.com,单击 Register(注册)链接;
——————————
① 翻译本书时,wrox.com 中下载本书代码的短地址为:http://tinyurl.com/projs-3rd-code。
② 您也可以登录图灵社区(http://www.ituring.com.cn/),在本书页面中提交您发现的错误。
图灵社区会员 StinkBC(StinkBC@gmail.com) 专享 尊重版权
6 前 言
(2) 阅读使用条款并单击 Agree(同意);
(3) 完成必填信息和您愿意提供的可选信息,然后单击 Submit(提交);
(4) 随后,您会收到一封电子邮件,其中包含如何验证账号和完成注册过程的信息。
如果不加入 P2P 论坛,虽然也可以阅读其中的帖子,但却不能发表帖子,只有注
册后才能发表。
在加入论坛后,既可以发表新帖子也可以回复其他用户的帖子。可以在任何时间上网浏览论坛中的
帖子。如果希望将某个论坛中的新帖子通过电子邮件发送给您,请在论坛列表中单击与论坛名相关的
Subscribe to this Forum(订阅这个论坛)图标。
如果想了解有关如何使用 Wrox P2P 的更多信息,请阅读包含论坛规则、P2P 及 Wrox 图书常见问题
的 P2P FAQ;要阅读 FAQ,可以在任何 P2P 页面中单击 FAQ 链接。
致谢
虽然作者的名字被印在了封面上,但一个人是不可能完成这本书的,我想感谢与出版本书有关的一
些人。
首先,感谢 John Wiley & Sons 继续给我写作的机会。当时,出版本书第 1 版时,他们是唯一愿意承
担风险的一家出版社。对此,我将永远铭记于心。
感谢 John Wiley & Sons 的编辑人员,特别是 Kevin Kent 和 John Peloquin,他们卓有成效的工作使我
保持了坦诚直率的风格,也解决了我在写作期间不断变更内容的问题。
还要感谢对本书草稿给出反馈意见的所有人:Rob Friesel、Sergey Ilinsky、Dan Kielp、Peter-Paul Koch、
Jeremy McPeak、Alex Petrescu、Dmitry Soshnikov 和 Juriy “Kangax” Zaytsev。你们的宝贵意见让我自
己都为本书感到骄傲。
我想特别感谢 Brendan Eich,感谢他纠正了第 1 章中有关 JavaScript 历史的细节问题。
最后,当然也是非常重要的,感谢 Rey Bango 为本书作序。很高兴在与 Rey 通过网络认识几年之后,
终于在 2010 年有缘相见。他是这个行业里真正出色的人,我非常荣幸能请到他为本书作序。
关于技术编辑
John Peloquin 是一位有十多年 JavaScript 经验的前端工程师,开发过各种规模的应用。John 拥有加
州大学伯克利分校的数学学士学位,目前在一家致力于卫生保健的创业公司担任开发主管。在编辑本书
之前,John 编辑过 Jeremy McPeak 的 JavaScript 24-Hour Trainer(Wiley,2010)。编写代码和收集勘误
之余,John 经常沉迷于数学、哲学和魔术。
图灵社区会员 StinkBC(StinkBC@gmail.com) 专享 尊重版权
目 录 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
18
17
目 录
第 1 章 JavaScript 简介 .................................1
1.1 JavaScript 简史 ..........................................1
1.2 JavaScript 实现 ..........................................2
1.2.1 ECMAScript...................................3
1.2.2 文档对象模型(DOM)................5
1.2.3 浏览器对象模型(BOM) ............8
1.3 JavaScript 版本 ..........................................8
1.4 小结 ...........................................................9
第 2 章 在 HTML 中使用 JavaScript .........10
2.1 <script>元素........................................10
2.1.1 标签的位置 ..................................12
2.1.2 延迟脚本 ......................................13
2.1.3 异步脚本 ......................................13
2.1.4 在 XHTML 中的用法...................14
2.1.5 不推荐使用的语法.......................16
2.2 嵌入代码与外部文件...............................16
2.3 文档模式..................................................16
2.4 <noscript>元素 ...................................18
2.5 小结 .........................................................18
第 3 章 基本概念............................................19
3.1 语法 .........................................................19
3.1.1 区分大小写 ..................................19
3.1.2 标识符..........................................19
3.1.3 注释..............................................20
3.1.4 严格模式 ......................................20
3.1.5 语句..............................................20
3.2 关键字和保留字 ......................................21
3.3 变量 .........................................................22
3.4 数据类型..................................................23
3.4.1 typeof 操作符............................23
3.4.2 Undefined 类型 .........................24
3.4.3 Null 类型....................................25
3.4.4 Boolean 类型..............................26
3.4.5 Number 类型................................27
3.4.6 String 类型................................32
3.4.7 Object 类型................................35
3.5 操作符 .....................................................36
3.5.1 一元操作符 ..................................36
3.5.2 位操作符......................................39
3.5.3 布尔操作符 ..................................44
3.5.4 乘性操作符 ..................................47
3.5.5 加性操作符 ..................................48
3.5.6 关系操作符 ..................................50
3.5.7 相等操作符 ..................................51
3.5.8 条件操作符 ..................................53
3.5.9 赋值操作符 ..................................53
3.5.10 逗号操作符 ................................54
3.6 语句 .........................................................54
3.6.1 if 语句 ........................................54
3.6.2 do-while 语句...........................55
3.6.3 while 语句 .................................55
3.6.4 for 语句......................................56
3.6.5 for-in 语句 ...............................57
3.6.6 label 语句 .................................58
3.6.7 break 和 continue 语句 ..........58
3.6.8 with 语句....................................60
3.6.9 switch 语句 ...............................60
3.7 函数 .........................................................62
3.7.1 理解参数......................................64
3.7.2 没有重载......................................66
3.8 小结 .........................................................67
图灵社区会员 StinkBC(StinkBC@gmail.com) 专享 尊重版权
2 目 录
第 4 章 变量、作用域和内存问题..............68
4.1 基本类型和引用类型的值.......................68
4.1.1 动态的属性..................................68
4.1.2 复制变量值..................................69
4.1.3 传递参数......................................70
4.1.4 检测类型......................................72
4.2 执行环境及作用域 ..................................73
4.2.1 延长作用域链 ..............................75
4.2.2 没有块级作用域 ..........................76
4.3 垃圾收集 .................................................78
4.3.1 标记清除......................................78
4.3.2 引用计数......................................79
4.3.3 性能问题......................................80
4.3.4 管理内存......................................81
4.4 小结 .........................................................81
第 5 章 引用类型............................................83
5.1 Object 类型...........................................83
5.2 Array 类型 .............................................86
5.2.1 检测数组......................................88
5.2.2 转换方法......................................89
5.2.3 栈方法..........................................90
5.2.4 队列方法......................................91
5.2.5 重排序方法..................................92
5.2.6 操作方法......................................94
5.2.7 位置方法......................................95
5.2.8 迭代方法......................................96
5.2.9 归并方法......................................97
5.3 Date 类型 ...............................................98
5.3.1 继承的方法................................100
5.3.2 日期格式化方法 ........................101
5.3.3 日期/时间组件方法 ...................102
5.4 RegExp 类型 .........................................103
5.4.1 RegExp 实例属性......................105
5.4.2 RegExp 实例方法......................106
5.4.3 RegExp 构造函数属性..............107
5.4.4 模式的局限性 ............................109
5.5 Function 类型.....................................110
5.5.1 没有重载(深入理解).............111
5.5.2 函数声明与函数表达式.............111
5.5.3 作为值的函数............................ 112
5.5.4 函数内部属性............................ 113
5.5.5 函数属性和方法 ........................ 116
5.6 基本包装类型........................................ 118
5.6.1 Boolean 类型........................... 120
5.6.2 Number 类型............................. 120
5.6.3 String 类型............................. 122
5.7 单体内置对象........................................ 130
5.7.1 Global 对象............................. 131
5.7.2 Math 对象 ................................. 134
5.8 小结....................................................... 137
第 6 章 面向对象的程序设计 .................... 138
6.1 理解对象 ............................................... 138
6.1.1 属性类型.................................... 139
6.1.2 定义多个属性............................ 142
6.1.3 读取属性的特性 ........................ 143
6.2 创建对象 ............................................... 144
6.2.1 工厂模式.................................... 144
6.2.2 构造函数模式............................ 144
6.2.3 原型模式.................................... 147
6.2.4 组合使用构造函数模式和原型
模式 ........................................... 159
6.2.5 动态原型模式............................ 159
6.2.6 寄生构造函数模式 .................... 160
6.2.7 稳妥构造函数模式 .................... 161
6.3 继承....................................................... 162
6.3.1 原型链 ....................................... 162
6.3.2 借用构造函数............................ 167
6.3.3 组合继承.................................... 168
6.3.4 原型式继承................................ 169
6.3.5 寄生式继承................................ 171
6.3.6 寄生组合式继承 ........................ 172
6.4 小结....................................................... 174
第 7 章 函数表达式 ..................................... 175
7.1 递归....................................................... 177
7.2 闭包....................................................... 178
7.2.1 闭包与变量................................ 181
7.2.2 关于 this 对象......................... 182
7.2.3 内存泄漏.................................... 183
图灵社区会员 StinkBC(StinkBC@gmail.com) 专享 尊重版权
目 录 3
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
18
17
7.3 模仿块级作用域 ....................................184
7.4 私有变量................................................186
7.4.1 静态私有变量 ............................188
7.4.2 模块模式 ....................................189
7.4.3 增强的模块模式.........................191
7.5 小结 .......................................................192
第 8 章 BOM .................................................193
8.1 window 对象 .........................................193
8.1.1 全局作用域 ................................193
8.1.2 窗口关系及框架.........................194
8.1.3 窗口位置 ....................................197
8.1.4 窗口大小 ....................................198
8.1.5 导航和打开窗口.........................199
8.1.6 间歇调用和超时调用.................203
8.1.7 系统对话框 ................................205
8.2 location 对象.....................................207
8.2.1 查询字符串参数.........................207
8.2.2 位置操作 ....................................208
8.3 navigator 对象...................................210
8.3.1 检测插件 ....................................211
8.3.2 注册处理程序 ............................213
8.4 screen 对象 .........................................214
8.5 history 对象.......................................215
8.6 小结 .......................................................216
第 9 章 客户端检测......................................217
9.1 能力检测................................................217
9.1.1 更可靠的能力检测.....................218
9.1.2 能力检测,不是浏览器检测......220
9.2 怪癖检测................................................220
9.3 用户代理检测 ........................................221
9.3.1 用户代理字符串的历史 .............222
9.3.2 用户代理字符串检测技术 .........228
9.3.3 完整的代码 ................................242
9.3.4 使用方法 ....................................245
9.4 小结 .......................................................246
第 10 章 DOM...............................................247
10.1 节点层次..............................................247
10.1.1 Node 类型..............................248
10.1.2 Document 类型.....................253
10.1.3 Element 类型 .......................261
10.1.4 Text 类型..............................270
10.1.5 Comment 类型 .......................273
10.1.6 CDATASection 类型 ............274
10.1.7 DocumentType 类型 ............274
10.1.8 DocumentFragment 类型....275
10.1.9 Attr 类型..............................276
10.2 DOM 操作技术....................................277
10.2.1 动态脚本................................277
10.2.2 动态样式................................279
10.2.3 操作表格................................281
10.2.4 使用 NodeList .....................283
10.3 小结 .....................................................284
第 11 章 DOM 扩展 .....................................286
11.1 选择符 API ..........................................286
11.1.1 querySelector()方法.......286
11.1.2 querySelectorAll()
方法........................................287
11.1.3 matchesSelector()
方法........................................288
11.2 元素遍历..............................................288
11.3 HTML5 ................................................289
11.3.1 与类相关的扩充.....................289
11.3.2 焦点管理................................291
11.3.3 HTMLDocument 的变化 ........292
11.3.4 字符集属性 ............................293
11.3.5 自定义数据属性.....................293
11.3.6 插入标记................................294
11.3.7 scrollIntoView()方法.....298
11.4 专有扩展..............................................298
11.4.1 文档模式................................298
11.4.2 children 属性.....................299
11.4.3 contains()方法..................300
11.4.4 插入文本................................301
11.4.5 滚动........................................303
11.5 小结 .....................................................304
图灵社区会员 StinkBC(StinkBC@gmail.com) 专享 尊重版权
4 目 录
第 12 章 DOM2 和 DOM3 .........................305
12.1 DOM 变化 ...........................................305
12.1.1 针对 XML 命名空间的变化....306
12.1.2 其他方面的变化.....................309
12.2 样式 .....................................................312
12.2.1 访问元素的样式.....................313
12.2.2 操作样式表 ............................317
12.2.3 元素大小................................320
12.3 遍历 .....................................................326
12.3.1 NodeIterator.....................328
12.3.2 TreeWalker .........................330
12.4 范围 .....................................................332
12.4.1 DOM 中的范围 ......................332
12.4.2 IE8 及更早版本中的范围.......340
12.5 小结 .....................................................343
第 13 章 事件................................................345
13.1 事件流 .................................................345
13.1.1 事件冒泡................................346
13.1.2 事件捕获................................346
13.1.3 DOM 事件流 ..........................347
13.2 事件处理程序......................................348
13.2.1 HTML 事件处理程序.............348
13.2.2 DOM0 级事件处理程序.........350
13.2.3 DOM2 级事件处理程序.........351
13.2.4 IE 事件处理程序....................352
13.2.5 跨浏览器的事件处理程序 .....353
13.3 事件对象..............................................355
13.3.1 DOM 中的事件对象...............355
13.3.2 IE 中的事件对象....................358
13.3.3 跨浏览器的事件对象.............360
13.4 事件类型..............................................362
13.4.1 UI 事件...................................362
13.4.2 焦点事件................................367
13.4.3 鼠标与滚轮事件.....................368
13.4.4 键盘与文本事件.....................379
13.4.5 复合事件................................384
13.4.6 变动事件................................385
13.4.7 HTML5 事件..........................388
13.4.8 设备事件................................395
13.4.9 触摸与手势事件 .................... 399
13.5 内存和性能.......................................... 402
13.5.1 事件委托................................ 402
13.5.2 移除事件处理程序 ................ 404
13.6 模拟事件 ............................................. 405
13.6.1 DOM 中的事件模拟 .............. 405
13.6.2 IE 中的事件模拟.................... 410
13.7 小结..................................................... 411
第 14 章 表单脚本....................................... 412
14.1 表单的基础知识.................................. 412
14.1.1 提交表单................................ 413
14.1.2 重置表单................................ 414
14.1.3 表单字段................................ 414
14.2 文本框脚本.......................................... 419
14.2.1 选择文本................................ 420
14.2.2 过滤输入................................ 423
14.2.3 自动切换焦点 ........................ 426
14.2.4 HTML5 约束验证 API........... 427
14.3 选择框脚本.......................................... 431
14.3.1 选择选项................................ 432
14.3.2 添加选项................................ 434
14.3.3 移除选项................................ 435
14.3.4 移动和重排选项 .................... 435
14.4 表单序列化.......................................... 436
14.5 富文本编辑.......................................... 438
14.5.1 使用 contenteditable
属性 ....................................... 438
14.5.2 操作富文本............................ 439
14.5.3 富文本选区............................ 441
14.5.4 表单与富文本 ........................ 443
14.6 小结..................................................... 443
第 15 章 使用 Canvas 绘图....................... 445
15.1 基本用法 ............................................. 445
15.2 2D 上下文............................................ 446
15.2.1 填充和描边............................ 446
15.2.2 绘制矩形................................ 447
15.2.3 绘制路径................................ 449
15.2.4 绘制文本................................ 451
15.2.5 变换 ....................................... 453
图灵社区会员 StinkBC(StinkBC@gmail.com) 专享 尊重版权
目 录 5
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
18
17
15.2.6 绘制图像 ................................456
15.2.7 阴影........................................457
15.2.8 渐变........................................458
15.2.9 模式........................................460
15.2.10 使用图像数据.......................460
15.2.11 合成......................................462
15.3 WebGL.................................................463
15.3.1 类型化数组 ............................463
15.3.2 WebGL 上下文.......................468
15.3.3 支持........................................478
15.4 小结 .....................................................478
第 16 章 HTML5 脚本编程.........................480
16.1 跨文档消息传递 ..................................480
16.2 原生拖放..............................................481
16.2.1 拖放事件 ................................482
16.2.2 自定义放置目标.....................482
16.2.3 dataTransfer 对象 ............483
16.2.4 dropEffect 与
effectAllowed ...................484
16.2.5 可拖动 ....................................485
16.2.6 其他成员 ................................485
16.3 媒体元素..............................................486
16.3.1 属性........................................487
16.3.2 事件........................................488
16.3.3 自定义媒体播放器.................488
16.3.4 检测编解码器的支持情况......489
16.3.5 Audio 类型............................490
16.4 历史状态管理 ......................................491
16.5 小结 .....................................................492
第 17 章 错误处理与调试...........................493
17.1 浏览器报告的错误...............................493
17.1.1 IE............................................493
17.1.2 Firefox ....................................494
17.1.3 Safari ......................................496
17.1.4 Opera ......................................497
17.1.5 Chrome ...................................498
17.2 错误处理..............................................499
17.2.1 try-catch 语句 ...................500
17.2.2 抛出错误 ................................503
17.2.3 错误(error)事件 .............505
17.2.4 处理错误的策略.....................506
17.2.5 常见的错误类型.....................507
17.2.6 区分致命错误和非致命
错误........................................510
17.2.7 把错误记录到服务器.............511
17.3 调试技术..............................................512
17.3.1 将消息记录到控制台.............512
17.3.2 将消息记录到当前页面 .........515
17.3.3 抛出错误................................515
17.4 常见的 IE 错误 ....................................516
17.4.1 操作终止................................516
17.4.2 无效字符................................518
17.4.3 未找到成员 ............................518
17.4.4 未知运行时错误.....................519
17.4.5 语法错误................................519
17.4.6 系统无法找到指定资源 .........519
17.5 小结 .....................................................520
第 18 章 JavaScript 与 XML .....................521
18.1 浏览器对 XML DOM 的支持..............521
18.1.1 DOM2 级核心 ........................521
18.1.2 DOMParser 类型...................522
18.1.3 XMLSerializer 类型 ..........523
18.1.4 IE8 及之前版本中的 XML.....523
18.1.5 跨浏览器处理 XML...............527
18.2 浏览器对 XPath 的支持.......................529
18.2.1 DOM3 级 XPath .....................529
18.2.2 IE 中的 XPath.........................534
18.2.3 跨浏览器使用 XPath..............535
18.3 浏览器对 XSLT 的支持.......................537
18.3.1 IE 中的 XSLT.........................537
18.3.2 XSLTProcessor 类型 ..........541
18.3.3 跨浏览器使用 XSLT..............543
18.4 小结 .....................................................544
第 19 章 E4X ................................................546
19.1 E4X 的类型..........................................546
19.1.1 XML 类型................................546
19.1.2 XMLList 类型 .......................547
19.1.3 Namespace 类型....................548
图灵社区会员 StinkBC(StinkBC@gmail.com) 专享 尊重版权
6 目 录
19.1.4 QName 类型............................549
19.2 一般用法..............................................550
19.2.1 访问特性................................551
19.2.2 其他节点类型 ........................552
19.2.3 查询........................................553
19.2.4 构建和操作 XML...................555
19.2.5 解析和序列化 ........................557
19.2.6 命名空间................................558
19.3 其他变化..............................................559
19.4 全面启用 E4X......................................560
19.5 小结 .....................................................561
第 20 章 JSON.............................................562
20.1 语法 .....................................................562
20.1.1 简单值....................................562
20.1.2 对象........................................563
20.1.3 数组........................................564
20.2 解析与序列化......................................565
20.2.1 JSON 对象..............................565
20.2.2 序列化选项 ............................566
20.2.3 解析选项................................569
20.3 小结 .....................................................570
第 21 章 Ajax 与 Comet.............................571
21.1 XMLHttpRequest 对象 .....................571
21.1.1 XHR 的用法 ............................573
21.1.2 HTTP 头部信息......................575
21.1.3 GET 请求................................576
21.1.4 POST 请求..............................577
21.2 XMLHttpRequest 2 级 .........................578
21.2.1 FormData..............................578
21.2.2 超时设定................................579
21.2.3 overrideMimeType()
方法........................................580
21.3 进度事件..............................................580
21.3.1 load 事件..............................580
21.3.2 progress 事件.....................581
21.4 跨源资源共享......................................582
21.4.1 IE 对 CORS 的实现................582
21.4.2 其他浏览器对 CORS 的
实现........................................584
21.4.3 Preflighted Reqeusts............... 584
21.4.4 带凭据的请求 ........................ 585
21.4.5 跨浏览器的 CORS................. 585
21.5 其他跨域技术...................................... 586
21.5.1 图像 Ping ............................... 586
21.5.2 JSONP.................................... 587
21.5.3 Comet..................................... 588
21.5.4 服务器发送事件 .................... 590
21.5.5 Web Sockets........................... 591
21.5.6 SSE 与 Web Sockets .............. 593
21.6 安全..................................................... 593
21.7 小结..................................................... 594
第 22 章 高级技巧....................................... 596
22.1 高级函数 ............................................. 596
22.1.1 安全的类型检测 .................... 596
22.1.2 作用域安全的构造函数......... 597
22.1.3 惰性载入函数 ........................ 600
22.1.4 函数绑定................................ 602
22.1.5 函数柯里化............................ 604
22.2 防篡改对象.......................................... 606
22.2.1 不可扩展对象 ........................ 606
22.2.2 密封的对象............................ 607
22.2.3 冻结的对象............................ 608
22.3 高级定时器.......................................... 609
22.3.1 重复的定时器 ........................ 610
22.3.2 Yielding Processes................. 612
22.3.3 函数节流................................ 614
22.4 自定义事件.......................................... 616
22.5 拖放..................................................... 618
22.5.1 修缮拖动功能 ........................ 620
22.5.2 添加自定义事件 .................... 622
22.6 小结..................................................... 624
第 23 章 离线应用与客户端存储.............. 626
23.1 离线检测 ............................................. 626
23.2 应用缓存 ............................................. 627
23.3 数据存储 ............................................. 628
23.3.1 Cookie.................................... 629
23.3.2 IE 用户数据 ........................... 637
图灵社区会员 StinkBC(StinkBC@gmail.com) 专享 尊重版权
目 录 7
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
18
17
23.3.3 Web 存储机制 ........................638
23.3.4 IndexedDB..............................643
23.4 小结 .....................................................654
第 24 章 最佳实践........................................656
24.1 可维护性..............................................656
24.1.1 什么是可维护的代码 .............656
24.1.2 代码约定 ................................657
24.1.3 松散耦合 ................................659
24.1.4 编程实践 ................................662
24.2 性能 .....................................................666
24.2.1 注意作用域 ............................666
24.2.2 选择正确方法.........................667
24.2.3 最小化语句数.........................672
24.2.4 优化 DOM 交互......................673
24.3 部署 .....................................................676
24.3.1 构建过程 ................................676
24.3.2 验证........................................677
24.3.3 压缩........................................679
24.4 小结 .....................................................681
第 25 章 新兴的 API....................................682
25.1 requestAnimationFrame()...........682
25.1.1 早期动画循环.........................682
25.1.2 循环间隔的问题.....................683
25.1.3 mozRequestAnimationFrame.....................................683
25.1.4 webkitRequestAnimationFrame 与 msRequestAnimationFrame.................685
25.2 Page Visibility API ..............................686
25.3 Geolocation API...................................687
25.4 File API................................................689
25.4.1 FileReader 类型.................690
25.4.2 读取部分内容 ........................692
25.4.3 对象 URL ...............................693
25.4.4 读取拖放的文件.....................694
25.4.5 使用 XHR 上传文件...............695
25.5 Web 计时 .............................................696
25.6 Web Workers .......................................697
25.6.1 使用 Worker...........................697
25.6.2 Worker 全局作用域................698
25.6.3 包含其他脚本 ........................699
25.6.4 Web Workers 的未来 .............700
25.7 小结 .....................................................700
附录 A ECMAScript Harmony .................701
附录 B 严格模式 ..........................................717
附录 C JavaScript 库..................................723
附录 D JavaScript 工具 .............................727
图灵社区会员 StinkBC(StinkBC@gmail.com) 专享 尊重版权
1.1 JavaScript 简史 1
1
2
3
4
5
13
6
7
8
9
10
11
12
JavaScript 简介
本章内容
JavaScript 历史回顾
JavaScript 是什么
JavaScript 与 ECMAScript 的关系
JavaScript 的不同版本
avaScript 诞生于 1995 年。当时,它的主要目的是处理以前由服务器端语言(如 Perl)负责的一
些输入验证操作。在 JavaScript 问世之前,必须把表单数据发送到服务器端才能确定用户是否
没有填写某个必填域,是否输入了无效的值。Netscape Navigator 希望通过 JavaScript 来解决这个问题。
在人们普遍使用电话拔号上网的年代,能够在客户端完成一些基本的验证任务绝对是令人兴奋的。毕竟,
拨号上网的速度之慢,导致了与服务器的每一次数据交换事实上都成了对人们耐心的一次考验。
自此以后,JavaScript 逐渐成为市面上常见浏览器必备的一项特色功能。如今,JavaScript 的用途早
已不再局限于简单的数据验证,而是具备了与浏览器窗口及其内容等几乎所有方面交互的能力。今天的
JavaScript 已经成为一门功能全面的编程语言,能够处理复杂的计算和交互,拥有了闭包、匿名(lamda,
拉姆达)函数,甚至元编程等特性。作为 Web 的一个重要组成部分,JavaScript 的重要性是不言而喻的,
就连手机浏览器,甚至那些专为残障人士设计的浏览器等非常规浏览器都支持它。当然,微软的例子更
为典型。虽然有自己的客户端脚本语言 VBScript,但微软仍然在 Internet Explorer 的早期版本中加入了
自己的 JavaScript 实现①。
JavaScript 从一个简单的输入验证器发展成为一门强大的编程语言,完全出乎人们的意料。应该说,
它既是一门非常简单的语言,又是一门非常复杂的语言。说它简单,是因为学会使用它只需片刻功夫;
而说它复杂,是因为要真正掌握它则需要数年时间。要想全面理解和掌握 JavaScript,关键在于弄清楚
它的本质、历史和局限性。
1.1 JavaScript 简史
在 Web 日益流行的同时,人们对客户端脚本语言的需求也越来越强烈。那个时候,绝大多数因
特网用户都使用速度仅为 28.8kbit/s 的“猫”(调制解调器)上网,但网页的大小和复杂性却不断增
加。为完成简单的表单验证而频繁地与服务器交换数据只会加重用户的负担。想象一下:用户填写
完一个表单,单击“提交”按钮,然后等待 30 秒钟,最终服务器返回消息说有一个必填字段没有
——————————
① 对 IE 而言,当我们提到 JavaScript 时,实际上就是指 IE 对 JavaScript(ECMAScript)的实现——JScript。最早的 JScript
基于 Netscape JavaScript 1.0 开发,于 1996 年 8 月随同 Internet Explorer 3.0 发布。
J
第 1 章
图灵社区会员 StinkBC(StinkBC@gmail.com) 专享 尊重版权
2 第 1 章 JavaScript 简介
填好……当时走在技术革新最前沿的 Netscape 公司,决定着手开发一种客户端语言,用来处理这种
简单的验证。
当时就职于 Netscape 公司的布兰登·艾奇(Brendan Eich),开始着手为计划于 1995 年 2 月发布的
Netscape Navigator 2 开发一种名为 LiveScript 的脚本语言——该语言将同时在浏览器和服务器中使用
(它在服务器上的名字叫 LiveWire)。为了赶在发布日期前完成 LiveScript 的开发,Netscape 与 Sun 公司
建立了一个开发联盟。在 Netscape Navigator 2 正式发布前夕,Netscape 为了搭上媒体热炒 Java 的顺风车,
临时把 LiveScript 改名为 JavaScript。
由于 JavaScript 1.0 获得了巨大成功,Netscape 随即在 Netscape Navigator 3 中又发布了 JavaScript 1.1。
Web 虽然羽翼未丰,但用户关注度却屡创新高。在这样的背景下,Netscape 把自己定位为市场领袖型公
司。与此同时,微软决定向与 Navigator 竞争的自家产品 Internet Explorer 浏览器投入更多资源。Netscape
Navigator 3 发布后不久,微软就在其 Internet Explorer 3 中加入了名为 JScript 的 JavaScript 实现(命名为
JScript 是为了避开与 Netscape 有关的授权问题)。以现在的眼光来看,微软 1996 年 8 月为进入 Web 浏览
器领域而实施的这个重大举措,是导致 Netscape 日后蒙羞的一个标志性事件。然而,这个重大举措同时
也标志着 JavaScript 作为一门语言,其开发向前迈进了一大步。
微软推出其 JavaScript 实现意味着有了两个不同的 JavaScript 版本:Netscape Navigator 中的
JavaScript、Internet Explorer 中的 JScript。与 C 及其他编程语言不同,当时还没有标准规定 JavaScript 的
语法和特性,两个不同版本并存的局面已经完全暴露了这个问题。随着业界担心的日益加剧,JavaScript
的标准化问题被提上了议事日程。
1997 年,以 JavaScript 1.1 为蓝本的建议被提交给了欧洲计算机制造商协会(ECMA,European
Computer Manufacturers Association)。该协会指定 39 号技术委员会(TC39,Technical Committee #39)
负责“标准化一种通用、跨平台、供应商中立的脚本语言的语法和语义”(http://www.ecma
international.org/memento/TC39.htm)。TC39 由来自 Netscape、Sun、微软、Borland 及其他关注脚本语言
发展的公司的程序员组成,他们经过数月的努力完成了 ECMA-262——定义一种名为 ECMAScript(发
音为“ek-ma-script”)的新脚本语言的标准。
第二年,ISO/IEC(International Organization for Standardization and International Electrotechnical
Commission,国标标准化组织和国际电工委员会)也采用了 ECMAScript 作为标准(即 ISO/IEC-16262)。
自此以后,浏览器开发商就开始致力于将 ECMAScript 作为各自 JavaScript 实现的基础,也在不同程度
上取得了成功。
1.2 JavaScript 实现
虽然 JavaScript 和 ECMAScript 通常都被人们用来表达
相同的含义,但 JavaScript 的含义却比 ECMA-262 中规定的
要多得多。没错,一个完整的 JavaScript 实现应该由下列三
个不同的部分组成(见图 1-1)。
核心(ECMAScript)
文档对象模型(DOM)
浏览器对象模型(BOM) 图 1-1
图灵社区会员 StinkBC(StinkBC@gmail.com) 专享 尊重版权
1.2 JavaScript 实现 3
1
2
3
4
5
13
6
7
8
9
10
11
12
1.2.1 ECMAScript
由 ECMA-262 定义的 ECMAScript 与 Web 浏览器没有依赖关系。实际上,这门语言本身并不包含输
入和输出定义。ECMA-262 定义的只是这门语言的基础,而在此基础之上可以构建更完善的脚本语言。
我们常见的 Web 浏览器只是 ECMAScript 实现可能的宿主环境之一。宿主环境不仅提供基本的
ECMAScript 实现,同时也会提供该语言的扩展,以便语言与环境之间对接交互。而这些扩展——如
DOM,则利用 ECMAScript 的核心类型和语法提供更多更具体的功能,以便实现针对环境的操作。其他
宿主环境包括 Node(一种服务端 JavaScript 平台)和 Adobe Flash。
既然 ECMA-262 标准没有参照 Web 浏览器,那它都规定了些什么内容呢?大致说来,它规定了这
门语言的下列组成部分:
语法
类型
语句
关键字
保留字
操作符
对象
ECMAScript 就是对实现该标准规定的各个方面内容的语言的描述。JavaScript 实现了 ECMAScript,
Adobe ActionScript 同样也实现了 ECMAScript。
1. ECMAScript 的版本
ECMAScript 的不同版本又称为版次,以第 x 版表示(意即描述特定实现的 ECMA-262 规范的第 x
个版本)。ECMA-262 的最近一版是第 5 版,发布于 2009 年。而 ECMA-262 的第 1 版本质上与 Netscape
的 JavaScript 1.1 相同——只不过删除了所有针对浏览器的代码并作了一些较小的改动:ECMA-262 要求
支持 Unicode 标准(从而支持多语言开发),而且对象也变成了平台无关的(Netscape JavaScript 1.1 的对
象在不同平台中的实现不一样,例如 Date 对象)。这也是 JavaScript 1.1 和 1.2 与 ECMA-262 第 1 版不一
致的主要原因。
ECMA-262 第 2 版主要是编辑加工的结果。这一版中内容的更新是为了与 ISO/IEC-16262 保持严格
一致,没有作任何新增、修改或删节处理。因此,一般不使用第 2 版来衡量 ECMAScript 实现的兼容性。
ECMA-262 第 3 版才是对该标准第一次真正的修改。修改的内容涉及字符串处理、错误定义和数
值输出。这一版还新增了对正则表达式、新控制语句、try-catch 异常处理的支持,并围绕标准的
国际化做出了一些小的修改。从各方面综合来看,第 3 版标志着 ECMAScript 成为了一门真正的编程
语言。
ECMA-262 第 4 版对这门语言进行了一次全面的检核修订。由于 JavaScript 在 Web 上日益流行,开
发人员纷纷建议修订 ECMAScript,以使其能够满足不断增长的 Web 开发需求。作为回应,ECMA TC39
重新召集相关人员共同谋划这门语言的未来。结果,出台后的标准几乎在第 3 版基础上完全定义了一门
新语言。第 4 版不仅包含了强类型变量、新语句和新数据结构、真正的类和经典继承,还定义了与数据
交互的新方式。
与此同时,TC39 下属的一个小组也提出了一个名为 ECMAScript 3.1 的替代性建议,该建议只对这
门语言进行了较少的改进。这个小组认为第 4 版给这门语言带来的跨越太大了。因此,该小组建议对这
图灵社区会员 StinkBC(StinkBC@gmail.com) 专享 尊重版权
4 第 1 章 JavaScript 简介
门语言进行小幅修订,能够在现有 JavaScript 引擎基础上实现。最终,ES3.1 附属委员会获得的支持超过
了 TC39,ECMA-262 第 4 版在正式发布前被放弃。
ECMAScript 3.1 成为 ECMA-262 第 5 版,并于 2009 年 12 月 3 日正式发布。第 5 版力求澄清第 3
版中已知的歧义并增添了新的功能。新功能包括原生 JSON 对象(用于解析和序列化 JSON 数据)、继
承的方法和高级属性定义,另外还包含一种严格模式,对 ECMAScript 引擎解释和执行代码进行了补充
说明。
2. 什么是 ECMAScript 兼容
ECMA-262 给出了 ECMAScript 兼容的定义。要想成为 ECMAScript 的实现,则该实现必须做到:
支持 ECMA-262 描述的所有“类型、值、对象、属性、函数以及程序句法和语义”(ECMA-262
第 1 页);
支持 Unicode 字符标准。
此外,兼容的实现还可以进行下列扩展。
添加 ECMA-262 没有描述的“更多类型、值、对象、属性和函数”。ECMA-262 所说的这些新增
特性,主要是指该标准中没有规定的新对象和对象的新属性。
支持 ECMA-262 没有定义的“程序和正则表达式语法”。(也就是说,可以修改和扩展内置的正
则表达式语法。)
上述要求为兼容实现的开发人员基于 ECMAScript 开发一门新语言提供了广阔的空间和极大的灵活
性,这也从另一个侧面说明了 ECMAScript 受开发人员欢迎的原因。
3. Web 浏览器对 ECMAScript 的支持
1996 年,Netscape Navigator 3 捆绑发布了 JavaScript 1.1。而相同的 JavaScript 1.1 设计规范随后作为
对新标准(ECMA-262)的建议被提交给 Ecma。伴随着 JavaScript 的迅速走红,Netscape 豪情满怀地着
手开发 JavaScript 1.2。然而,问题是 Ecma 当时还没有接受 Netscape 的建议。
Netscape Navigator 3 发布后不久,微软也推出了 Internet Explorer 3。微软在 IE 的这一版中捆绑了
JScript 1.0,很多人都认为 JScript 1.0 与 JavaScript 1.1 应该是一样的。但是,由于没有文档依据,加之不
适当的特性模仿,JScript 1.0 还是很难与 JavaScript 1.1 相提并论。
1997 年,内置 JavaScript 1.2 的 Netscape Navigator 4 发布;而到这一年年底,ECMA-262 第 1 版也
被接受并实现了标准化。结果,虽然 ECMAScript 被认为是基于 JavaScript 1.1 制定的,但 JavaScript 1.2
与 ECMAScript 的第 1 版并不兼容。
JScript 的升级版是 Internet Explorer 4 中内置的 JScript 3.0(随同微软 IIS 3.0 发布的 JScript 2.0 从来
也没有移植到浏览器中)。微软通过媒体大肆宣传 JScript 3.0 是世界上第一个 ECMA 兼容的脚本语言,
但当时的 ECMA-262 尚未定稿。于是,JScript 3.0 与 JavaScript 1.2 都遭遇了相同的尴尬局面——谁都没
有按照最终的 ECMAScript 标准来实现。
Netscape 决定更新其 JavaScript 实现,即在 Netscape Navigator 4.06 中发布 JavaScript 1.3,从而做到
了与 ECMA-262 的第一个版本完全兼容。在 JavaScript 1.3 中,Netscape 增加了对 Unicode 标准的支持,
并在保留 JavaScript 1.2 新增特性的同时实现了所有对象的平台中立化。
在 Netscape 以 Mozilla 项目的名义开放其源代码时,预期 JavaScript 1.4 将随同 Netscape Navigator 5
一道发布。然而,一个激进的决定,彻底重新设计 Netscape 代码,打乱了原有计划。后来,JavaScript 1.4
只发布了针对 Netscape Enterprise Server 的服务器版,而没有内置于 Web 浏览器中。
到了 2008 年,五大主流 Web 浏览器(IE、Firefox、Safari、Chrome 和 Opera)全部做到了与 ECMA-262
图灵社区会员 StinkBC(StinkBC@gmail.com) 专享 尊重版权
1.2 JavaScript 实现 5
1
2
3
4
5
13
6
7
8
9
10
11
12
兼容。IE8 是第一个着手实现 ECMA-262 第 5 版的浏览器,并在 IE9 中提供了完整的支持。Firefox 4 也
紧随其后做到兼容。下表列出了 ECMAScript 受主流 Web 浏览器支持的情况。
浏 览 器 ECMAScript兼容性 浏 览 器 ECMAScript兼容性
Netscape Navigator 2 — Opera 6~7.1 第2版
Netscape Navigator 3 — Opera 7.2+ 第3版
Netscape Navigator 4~4.05 — Safari 1~2.0.x 第3版*
Netscape Navigator 4.06~4.79 第1版 Safari 3.x 第3版
Netscape 6+(Mozilla 0.6.0+) 第3版 Safari 4.x~5.x 第5版*
IE3 — Chrome 1+ 第3版
IE4 — Firefox 1~2 第3版
IE5 第1版 Firefox 3.0.x 第3版
IE5.5~IE7 第3版 Firefox 3.5~3.6 第5版*
IE8 第5版* Firefox 4.0 + 第5版
IE9+ 第5版
* 不完全兼容的实现
1.2.2 文档对象模型(DOM)
文档对象模型(DOM,Document Object Model)是针对 XML 但经过扩展用于 HTML 的应用程序编
程接口(API,Application Programming Interface)。DOM 把整个页面映射为一个多层节点结构。HTML
或 XML 页面中的每个组成部分都是某种类型的节点,这些节点又包含着不同类型的数据。看下面这个
HTML 页面:
<html>
<head>
<title>Sample Page</title>
</head>
<body>
<p>Hello World!</p>
</body>
</html>
在 DOM 中,这个页面可以通过图 1-2 所示的分层节点图表示。
通过 DOM 创建的这个表示文档的树形图,开发人员获得了控制页面内容和结构的主动权。借助
DOM 提供的 API,开发人员可以轻松自如地删除、添加、替换或修改任何节点。
1. 为什么要使用 DOM
在 Internet Explorer 4 和 Netscape Navigator 4 分别支持的不同形式的 DHTML(Dynamic HTML)基
础上,开发人员首次无需重新加载网页,就可以修改其外观和内容了。然而,DHTML 在给 Web 技术发
展带来巨大进步的同时,也带来了巨大的问题。由于 Netscape 和微软在开发 DHTML 方面各持己见,过
去那个只编写一个 HTML 页面就能够在任何浏览器中运行的时代结束了。
对开发人员而言,如果想继续保持 Web 跨平台的天性,就必须额外多做一些工作。而人们真正担
心的是,如果不对 Netscape 和微软加以控制,Web 开发领域就会出现技术上两强割据,浏览器互不兼
图灵社区会员 StinkBC(StinkBC@gmail.com) 专享 尊重版权
6 第 1 章 JavaScript 简介
容的局面。此时,负责制定 Web 通信标准的 W3C(World Wide Web Consortium,万维网联盟)开始着
手规划 DOM。
图 1-2
2. DOM 级别
DOM1 级(DOM Level 1)于 1998 年 10 月成为 W3C 的推荐标准。DOM1 级由两个模块组成:DOM
核心(DOM Core)和 DOM HTML。其中,DOM 核心规定的是如何映射基于 XML 的文档结构,以便
简化对文档中任意部分的访问和操作。DOM HTML 模块则在 DOM 核心的基础上加以扩展,添加了针
对 HTML 的对象和方法。
请读者注意,DOM 并不只是针对 JavaScript 的,很多别的语言也都实现了 DOM。
不过,在 Web 浏览器中,基于 ECMAScript 实现的 DOM 的确已经成为 JavaScript 这
门语言的一个重要组成部分。
如果说 DOM1 级的目标主要是映射文档的结构,那么 DOM2 级的目标就要宽泛多了。DOM2 级在
原来 DOM 的基础上又扩充了(DHTML 一直都支持的)鼠标和用户界面事件、范围、遍历(迭代 DOM
文档的方法)等细分模块,而且通过对象接口增加了对 CSS(Cascading Style Sheets,层叠样式表)的
支持。DOM1 级中的 DOM 核心模块也经过扩展开始支持 XML 命名空间。
DOM2 级引入了下列新模块,也给出了众多新类型和新接口的定义。
DOM 视图(DOM Views):定义了跟踪不同文档(例如,应用 CSS 之前和之后的文档)视图的
接口;
DOM 事件(DOM Events):定义了事件和事件处理的接口;
DOM 样式(DOM Style):定义了基于 CSS 为元素应用样式的接口;
DOM 遍历和范围(DOM Traversal and Range):定义了遍历和操作文档树的接口。
DOM3 级则进一步扩展了 DOM,引入了以统一方式加载和保存文档的方法——在 DOM 加载和保
存(DOM Load and Save)模块中定义;新增了验证文档的方法——在 DOM 验证(DOM Validation)模
图灵社区会员 StinkBC(StinkBC@gmail.com) 专享 尊重版权
1.2 JavaScript 实现 7
1
2
3
4
5
13
6
7
8
9
10
11
12
块中定义。DOM3 级也对 DOM 核心进行了扩展,开始支持 XML 1.0 规范,涉及 XML Infoset、XPath
和 XML Base。
在阅读 DOM 标准的时候,读者可能会看到 DOM0 级(DOM Level 0)的字眼。
实际上,DOM0 级标准是不存在的;所谓 DOM0 级只是 DOM 历史坐标中的一个参照
点而已。具体说来,DOM0 级指的是 Internet Explorer 4.0 和 Netscape Navigator 4.0 最
初支持的 DHTML。
3. 其他 DOM 标准
除了 DOM 核心和 DOM HTML 接口之外,另外几种语言还发布了只针对自己的 DOM 标准。下面
列出的语言都是基于 XML 的,每种语言的 DOM 标准都添加了与特定语言相关的新方法和新接口:
SVG(Scalable Vector Graphic,可伸缩矢量图)1.0;
MathML(Mathematical Markup Language,数学标记语言)1.0;
SMIL(Synchronized Multimedia Integration Language,同步多媒体集成语言)。
还有一些语言也开发了自己的 DOM 实现,例如 Mozilla 的 XUL(XML User Interface Language,XML
用户界面语言)。但是,只有上面列出的几种语言是 W3C 的推荐标准。
4. Web 浏览器对 DOM 的支持
在 DOM 标准出现了一段时间之后,Web 浏览器才开始实现它。微软在 IE5 中首次尝试实现 DOM,
但直到 IE5.5 才算是真正支持 DOM1 级。在随后的 IE6 和 IE7 中,微软都没有引入新的 DOM 功能,而
到了 IE8 才对以前 DOM 实现中的 bug 进行了修复。
Netscape 直到 Netscape 6(Mozilla 0.6.0)才开始支持 DOM。在 Netscape 7 之后,Mozilla 把开发重心转
向了 Firefox 浏览器。Firefox 3 完全支持 DOM1 级,几乎完全支持 DOM2 级,甚至还支持 DOM3 级的一部
分。(Mozilla 开发团队的目标是构建与标准 100%兼容的浏览器,而他们的努力也得到了回报。)
目前,支持 DOM 已经成为浏览器开发商的首要目标,主流浏览器每次发布新版本都会改进对 DOM
的支持。下表列出了主流浏览器对 DOM 标准的支持情况。
浏 览 器 DOM兼容性
Netscape Navigator 1. ~ 4.x —
Netscape 6+ (Mozilla 0.6.0+) 1级、2级(几乎全部)、3级(部分)
IE2~IE4.x —
IE5 1级(最小限度)
IE5.5~IE8 1级(几乎全部)
IE9+ 1级、2级、3级
Opera 1~6 —
Opera 7~8.x 1级(几乎全部)、2级(部分)
Opera 9~9.9 1级、2级(几乎全部)、3级(部分)
Opera 10+ 1级、2级、3级(部分)
Safari 1.0.x 1级
Safari 2+ 1级、2级(部分)
Chrome 1+ 1级、2级(部分)
Firefox 1+ 1级、2级(几乎全部)、3级(部分)
图灵社区会员 StinkBC(StinkBC@gmail.com) 专享 尊重版权
8 第 1 章 JavaScript 简介
1.2.3 浏览器对象模型(BOM)
Internet Explorer 3 和 Netscape Navigator 3 有一个共同的特色,那就是支持可以访问和操作浏览器窗
口的浏览器对象模型(BOM,Browser Object Model)。开发人员使用 BOM 可以控制浏览器显示的页面
以外的部分。而 BOM 真正与众不同的地方(也是经常会导致问题的地方),还是它作为 JavaScript 实现
的一部分但却没有相关的标准。这个问题在 HTML5 中得到了解决,HTML5 致力于把很多 BOM 功能写
入正式规范。HTML5 发布后,很多关于 BOM 的困惑烟消云散。
从根本上讲,BOM 只处理浏览器窗口和框架;但人们习惯上也把所有针对浏览器的 JavaScript 扩展
算作 BOM 的一部分。下面就是一些这样的扩展:
弹出新浏览器窗口的功能;
移动、缩放和关闭浏览器窗口的功能;
提供浏览器详细信息的 navigator 对象;
提供浏览器所加载页面的详细信息的 location 对象;
提供用户显示器分辨率详细信息的 screen 对象;
对 cookies 的支持;
像 XMLHttpRequest 和 IE 的 ActiveXObject 这样的自定义对象。
由于没有 BOM 标准可以遵循,因此每个浏览器都有自己的实现。虽然也存在一些事实标准,例如
要有 window 对象和 navigator 对象等,但每个浏览器都会为这两个对象乃至其他对象定义自己的属
性和方法。现在有了 HTML5,BOM 实现的细节有望朝着兼容性越来越高的方向发展。第 8 章将深入讨
论 BOM。
1.3 JavaScript 版本
作为 Netscape“继承人”的 Mozilla 公司,是目前唯一还在沿用最初的 JavaScript 版本编号序列的浏
览器开发商。在 Netscape 将源代码提交给开源的 Mozilla 项目的时候,JavaScript 在浏览器中的最后一个
版本号是 1.3。(如前所述,1.4 版是只针对服务器的实现。)后来,随着 Mozilla 基金会继续开发 JavaScript,
添加新的特性、关键字和语法,JavaScript 的版本号继续递增。下表列出了 Netscape/Mozilla 浏览器中
JavaScript 版本号的递增过程:
浏 览 器 JavaScript版本 浏 览 器 JavaScript版本
Netscape Navigator 2 1.0 Firefox 1.5 1.6
Netscape Navigator 3 1.1 Firefox 2 1.7
Netscape Navigator 4 1.2 Firefox 3 1.8
Netscape Navigator 4.06 1.3 Firefox 3.5 1.8.1
Netscape 6+(Mozilla 0.6.0+) 1.5 Firefox 3.6 1.8.2
Firefox 1 1.5
实际上,上表中的编号方案源自 Firefox 4 将内置 JavaScript 2.0 这一共识。因此,2.0 版之前每个递
增的版本号,表示的是相应实现与 JavaScript 2.0 开发目标还有多大的距离。虽然原计划是这样,但
JavaScript 的这种发展速度让这个计划不再可行。目前,JavaScript 2.0 还没有目标实现。
图灵社区会员 StinkBC(StinkBC@gmail.com) 专享 尊重版权
1.4 小结 9
1
2
3
4
5
13
6
7
8
9
10
11
12
请注意,只有 Netscape/Mozilla 浏览器才遵循这种编号模式。例如,IE 的 JScript
就采用了另一种版本命名方案。换句话说,JScript 的版本号与上表中 JavaScript 的版
本号之间不存在任何对应关系。而且,大多数浏览器在提及对 JavaScript 的支持情况
时,一般都以 ECMAScript 兼容性和对 DOM 的支持情况为准。
1.4 小结
JavaScript 是一种专为与网页交互而设计的脚本语言,由下列三个不同的部分组成:
ECMAScript,由 ECMA-262 定义,提供核心语言功能;
文档对象模型(DOM),提供访问和操作网页内容的方法和接口;
浏览器对象模型(BOM),提供与浏览器交互的方法和接口。
JavaScript 的这三个组成部分,在当前五个主要浏览器(IE、Firefox、Chrome、Safari 和 Opera)中
都得到了不同程度的支持。其中,所有浏览器对 ECMAScript 第 3 版的支持大体上都还不错,而对
ECMAScript 5 的支持程度越来越高,但对 DOM 的支持则彼此相差比较多。对已经正式纳入 HTML5 标
准的 BOM 来说,尽管各浏览器都实现了某些众所周知的共同特性,但其他特性还是会因浏览器而异。
图灵社区会员 StinkBC(StinkBC@gmail.com) 专享 尊重版权
10 第 2 章 在 HTML 中使用 JavaScript
在 HTML 中使用 JavaScript
本章内容
使用<script>元素
嵌入脚本与外部脚本
文档模式对 JavaScript 的影响
考虑禁用 JavaScript 的场景
要一提到把 JavaScript 放到网页中,就不得不涉及 Web 的核心语言——HTML。在当初开发
JavaScript 的时候,Netscape 要解决的一个重要问题就是如何做到让 JavaScript 既能与 HTML
页面共存,又不影响那些页面在其他浏览器中的呈现效果。经过尝试、纠错和争论,最终的决定就是
为 Web 增加统一的脚本支持。而 Web 诞生早期的很多做法也都保留了下来,并被正式纳入 HTML 规
范当中。
2.1 <script>元素
向 HTML 页面中插入 JavaScript 的主要方法,就是使用<script>元素。这个元素由 Netscape 创造
并在 Netscape Navigator 2 中首先实现。后来,这个元素被加入到正式的 HTML 规范中。HTML 4.01 为
<script>定义了下列 6 个属性。
async:可选。表示应该立即下载脚本,但不应妨碍页面中的其他操作,比如下载其他资源或
等待加载其他脚本。只对外部脚本文件有效。
charset:可选。表示通过 src 属性指定的代码的字符集。由于大多数浏览器会忽略它的值,
因此这个属性很少有人用。
defer:可选。表示脚本可以延迟到文档完全被解析和显示之后再执行。只对外部脚本文件有
效。IE7 及更早版本对嵌入脚本也支持这个属性。
language:已废弃。原来用于表示编写代码使用的脚本语言(如 JavaScript、JavaScript1.2
或 VBScript)。大多数浏览器会忽略这个属性,因此也没有必要再用了。
src:可选。表示包含要执行代码的外部文件。
type:可选。可以看成是 language 的替代属性;表示编写代码使用的脚本语言的内容类型(也
称为 MIME 类型)。虽然 text/javascript 和 text/ecmascript 都已经不被推荐使用,但人
们一直以来使用的都还是 text/javascript。实际上,服务器在传送 JavaScript 文件时使用的
MIME 类型通常是 application/x–javascript,但在 type 中设置这个值却可能导致脚本被
忽略。另外,在非IE浏览器中还可以使用以下值:application/javascript和application/
只
第 2 章
图灵社区会员 StinkBC(StinkBC@gmail.com) 专享 尊重版权
2.1 <script>元素 11
1
2
3
4
5
13
6
7
8
9
10
11
12
ecmascript。考虑到约定俗成和最大限度的浏览器兼容性,目前 type 属性的值依旧还是
text/javascript。不过,这个属性并不是必需的,如果没有指定这个属性,则其默认值仍为
text/javascript。
使用<script>元素的方式有两种:直接在页面中嵌入 JavaScript 代码和包含外部 JavaScript
文件。
在使用<script>元素嵌入 JavaScript 代码时,只须为<script>指定 type 属性。然后,像下面这
样把 JavaScript 代码直接放在元素内部即可:
<script type=\"text/javascript\">
function sayHi(){
alert(\"Hi!\");
}
</script>
包含在<script>元素内部的 JavaScript 代码将被从上至下依次解释。就拿前面这个例子来说,解释
器会解释一个函数的定义,然后将该定义保存在自己的环境当中。在解释器对<script>元素内部的所
有代码求值完毕以前,页面中的其余内容都不会被浏览器加载或显示。
在使用<script>嵌入 JavaScript 代码时,记住不要在代码中的任何地方出现\"</script>\"字符串。
例如,浏览器在加载下面所示的代码时就会产生一个错误:
<script type=\"text/javascript\">
function sayScript(){
alert(\"</script>\");
}
</script>
因为按照解析嵌入式代码的规则,当浏览器遇到字符串\"</script>\"时,就会认为那是结束的
</script>标签。而通过转义字符“/”可以解决这个问题,例如:
<script type=\"text/javascript\">
function sayScript(){
alert(\"<\\/script>\");
}
</script>
这样写代码浏览器可以接受,因而也就不会导致错误了。
如果要通过<script>元素来包含外部 JavaScript 文件,那么 src 属性就是必需的。这个属性的值
是一个指向外部 JavaScript 文件的链接,例如:
<script type=\"text/javascript\" src=\"example.js\"></script>
在这个例子中,外部文件 example.js 将被加载到当前页面中。外部文件只须包含通常要放在开始
的<script>和结束的</script>之间的那些 JavaScript 代码即可。与解析嵌入式 JavaScript 代码一样,
在解析外部 JavaScript 文件(包括下载该文件)时,页面的处理也会暂时停止。如果是在 XHTML 文档
中,也可以省略前面示例代码中结束的</script>标签,例如:
<script type=\"text/javascript\" src=\"example.js\" />
但是,不能在 HTML 文档使用这种语法。原因是这种语法不符合 HTML 规范,而且也得不到某些
浏览器(尤其是 IE)的正确解析。
图灵社区会员 StinkBC(StinkBC@gmail.com) 专享 尊重版权
12 第 2 章 在 HTML 中使用 JavaScript
按照惯例,外部 JavaScript 文件带有.js 扩展名。但这个扩展名不是必需的,因为
浏览器不会检查包含 JavaScript 的文件的扩展名。这样一来,使用 JSP、PHP 或其他
服务器端语言动态生成 JavaScript 代码也就成为了可能。但是,服务器通常还是需要
看扩展名决定为响应应用哪种 MIME 类型。如果不使用.js 扩展名,请确保服务器能
返回正确的 MIME 类型。
需要注意的是,带有 src 属性的<script>元素不应该在其<script>和</script>标签之间再
包含额外的 JavaScript 代码。如果包含了嵌入的代码,则只会下载并执行外部脚本文件,嵌入的代码
会被忽略。
另外,通过<script>元素的 src 属性还可以包含来自外部域的 JavaScript 文件。这一点既让
<script>元素倍显强大,又让它备受争议。在这一点上,<script>与<img>元素非常相似,即它的 src
属性可以是指向当前 HTML 页面所在域之外的某个域中的完整 URL,例如:
<script type=\"text/javascript\" src=\"http://www.somewhere.com/afile.js\"></script>
这样,位于外部域中的代码也会被加载和解析,就像这些代码位于加载它们的页面中一样。利用这
一点就可以在必要时通过不同的域来提供 JavaScript 文件。不过,在访问自己不能控制的服务器上的
JavaScript 文件时则要多加小心。如果不幸遇到了怀有恶意的程序员,那他们随时都可能替换该文件中
的代码。因此,如果想包含来自不同域的代码,则要么你是那个域的所有者,要么那个域的所有者值得
信赖。
无论如何包含代码,只要不存在 defer 和 async 属性,浏览器都会按照<script>元素在页面中
出现的先后顺序对它们依次进行解析。换句话说,在第一个<script>元素包含的代码解析完成后,第
二个<script>包含的代码才会被解析,然后才是第三个、第四个……
2.1.1 标签的位置
按照传统的做法,所有<script>元素都应该放在页面的<head>元素中,例如:
<!DOCTYPE html>
<html>
<head>
<title>Example HTML Page</title>
<script type=\"text/javascript\" src=\"example1.js\"></script>
<script type=\"text/javascript\" src=\"example2.js\"></script>
</head>
<body>
<!-- 这里放内容 -->
</body>
</html>
这种做法的目的就是把所有外部文件(包括 CSS 文件和 JavaScript 文件)的引用都放在相同的地方。
可是,在文档的<head>元素中包含所有 JavaScript 文件,意味着必须等到全部 JavaScript 代码都被下载、
解析和执行完成以后,才能开始呈现页面的内容(浏览器在遇到<body>标签时才开始呈现内容)。对于
那些需要很多 JavaScript 代码的页面来说,这无疑会导致浏览器在呈现页面时出现明显的延迟,而延迟
期间的浏览器窗口中将是一片空白。为了避免这个问题,现代 Web 应用程序一般都把全部 JavaScript 引
用放在<body>元素中页面内容的后面,如下例所示:
图灵社区会员 StinkBC(StinkBC@gmail.com) 专享 尊重版权
2.1 <script>元素 13
1
2
3
4
5
13
6
7
8
9
10
11
12
<!DOCTYPE html>
<html>
<head>
<title>Example HTML Page</title>
</head>
<body>
<!-- 这里放内容 -->
<script type=\"text/javascript\" src=\"example1.js\"></script>
<script type=\"text/javascript\" src=\"example2.js\"></script>
</body>
</html>
这样,在解析包含的 JavaScript 代码之前,页面的内容将完全呈现在浏览器中。而用户也会因为浏
览器窗口显示空白页面的时间缩短而感到打开页面的速度加快了。
2.1.2 延迟脚本
HTML 4.01 为<script>标签定义了 defer 属性。这个属性的用途是表明脚本在执行时不会影响页
面的构造。也就是说,脚本会被延迟到整个页面都解析完毕后再运行。因此,在<script>元素中设置
defer 属性,相当于告诉浏览器立即下载,但延迟执行。
<!DOCTYPE html>
<html>
<head>
<title>Example HTML Page</title>
<script type=\"text/javascript\" defer=\"defer\" src=\"example1.js\"></script>
<script type=\"text/javascript\" defer=\"defer\" src=\"example2.js\"></script>
</head>
<body>
<!-- 这里放内容 -->
</body>
</html>
在这个例子中,虽然我们把<script>元素放在了文档的<head>元素中,但其中包含的脚本将延迟
到浏览器遇到</html>标签后再执行。HTML5 规范要求脚本按照它们出现的先后顺序执行,因此第一
个延迟脚本会先于第二个延迟脚本执行,而这两个脚本会先于 DOMContentLoaded 事件(详见第 13 章)
执行。在现实当中,延迟脚本并不一定会按照顺序执行,也不一定会在 DOMContentLoaded 事件触发
前执行,因此最好只包含一个延迟脚本。
前面提到过,defer 属性只适用于外部脚本文件。这一点在 HTML5 中已经明确规定,因此支持
HTML5 的实现会忽略给嵌入脚本设置的 defer 属性。IE4~IE7 还支持对嵌入脚本的 defer 属性,但
IE8 及之后版本则完全支持 HTML5 规定的行为。
IE4、Firefox 3.5、Safari 5 和 Chrome 是最早支持 defer 属性的浏览器。其他浏览器会忽略这个属
性,像平常一样处理脚本。为此,把延迟脚本放在页面底部仍然是最佳选择。
在 XHTML 文档中,要把 defer 属性设置为 defer=\"defer\"。
2.1.3 异步脚本
HTML5 为<script>元素定义了 async 属性。这个属性与 defer 属性类似,都用于改变处理脚本
图灵社区会员 StinkBC(StinkBC@gmail.com) 专享 尊重版权
14 第 2 章 在 HTML 中使用 JavaScript
的行为。同样与 defer 类似,async 只适用于外部脚本文件,并告诉浏览器立即下载文件。但与 defer
不同的是,标记为 async 的脚本并不保证按照指定它们的先后顺序执行。例如:
<!DOCTYPE html>
<html>
<head>
<title>Example HTML Page</title>
<script type=\"text/javascript\" async src=\"example1.js\"></script>
<script type=\"text/javascript\" async src=\"example2.js\"></script>
</head>
<body>
<!-- 这里放内容 -->
</body>
</html>
在以上代码中,第二个脚本文件可能会在第一个脚本文件之前执行。因此,确保两者之间互不依赖
非常重要。指定 async 属性的目的是不让页面等待两个脚本下载和执行,从而异步加载页面其他内容。
为此,建议异步脚本不要在加载期间修改 DOM。
异步脚本一定会在页面的 load 事件前执行,但可能会在 DOMContentLoaded 事件触发之前或之
后执行。支持异步脚本的浏览器有 Firefox 3.6、Safari 5 和 Chrome。
在 XHTML 文档中,要把 async 属性设置为 async=\"async\"。
2.1.4 在XHTML中的用法①
可扩展超文本标记语言,即 XHTML(Extensible HyperText Markup Language),是将 HTML 作为
XML 的应用而重新定义的一个标准。编写 XHTML 代码的规则要比编写 HTML 严格得多,而且直接影
响能否在嵌入 JavaScript 代码时使用<script/>标签。以下面的代码块为例,虽然它们在 HTML 中是有
效的,但在 XHTML 中则是无效的。
<script type=\"text/javascript\">
function compare(a, b) {
if (a < b) {
alert(\"A is less than B\");
} else if (a > b) {
alert(\"A is greater than B\");
} else {
alert(\"A is equal to B\");
}
}
</script>
在 HTML 中,有特殊的规则用以确定<script>元素中的哪些内容可以被解析,但这些特殊的规则
在 XHTML 中不适用。这里比较语句 a < b 中的小于号(<)在 XHTML 中将被当作开始一个新标签来
解析。但是作为标签来讲,小于号后面不能跟空格,因此就会导致语法错误。
——————————
① HTML5 正快速地被前端开发人员采用,建议读者在学习和开发中遵循 HTML5 标准,本节内容可以跳过。
图灵社区会员 StinkBC(StinkBC@gmail.com) 专享 尊重版权
2.1 <script>元素 15
1
2
3
4
5
13
6
7
8
9
10
11
12
避免在 XHTML 中出现类似语法错误的方法有两个。一是用相应的 HTML 实体(<)替换代码
中所有的小于号(<),替换后的代码类似如下所示:
<script type=\"text/javascript\">
function compare(a, b) {
if (a < b) {
alert(\"A is less than B\");
} else if (a > b) {
alert(\"A is greater than B\");
} else {
alert(\"A is equal to B\");
}
}
</script>
虽然这样可以让代码在 XHTML 中正常运行,但却导致代码不好理解了。为此,我们可以考虑采用
另一个方法。
保证让相同代码在 XHTML 中正常运行的第二个方法,就是用一个 CData 片段来包含 JavaScript 代
码。在 XHTML(XML)中,CData 片段是文档中的一个特殊区域,这个区域中可以包含不需要解析的
任意格式的文本内容。因此,在 CData 片段中就可以使用任意字符——小于号当然也没有问题,而且不
会导致语法错误。引入 CData 片段后的 JavaScript 代码块如下所示:
<script type=\"text/javascript\"><![CDATA[
function compare(a, b) {
if (a < b) {
alert(\"A is less than B\");
} else if (a > b) {
alert(\"A is greater than B\");
} else {
alert(\"A is equal to B\");
}
}
]]></script>
在兼容 XHTML 的浏览器中,这个方法可以解决问题。但实际上,还有不少浏览器不兼容 XHTML,
因而不支持 CData 片段。怎么办呢?再使用 JavaScript 注释将 CData 标记注释掉就可以了:
<script type=\"text/javascript\">
//<![CDATA[
function compare(a, b) {
if (a < b) {
alert(\"A is less than B\");
} else if (a > b) {
alert(\"A is greater than B\");
} else {
alert(\"A is equal to B\");
}
}
//]]>
</script>
这种格式在所有现代浏览器中都可以正常使用。虽然有几分 hack 的味道,但它能通过 XHTML 验
证,而且对 XHTML 之前的浏览器也会平稳退化。
图灵社区会员 StinkBC(StinkBC@gmail.com) 专享 尊重版权
16 第 2 章 在 HTML 中使用 JavaScript
在将页面的 MIME 类型指定为\"application/xhtml+xml\"的情况下会触发
XHTML 模式。并不是所有浏览器都支持以这种方式提供 XHTML 文档。
2.1.5 不推荐使用的语法
在最早引入<script>元素的时候,该元素与传统 HTML 的解析规则是有冲突的。由于要对这个元
素应用特殊的解析规则,因此在那些不支持 JavaScript 的浏览器(最典型的是 Mosaic)中就会导致问题。
具体来说,不支持 JavaScript 的浏览器会把<script>元素的内容直接输出到页面中,因而会破坏页面的
布局和外观。
Netscape 与 Mosaic 协商并提出了一个解决方案,让不支持<script>元素的浏览器能够隐藏嵌入的
JavaScript 代码。这个方案就是把 JavaScript 代码包含在一个 HTML 注释中,像下面这样:
<script><!--
function sayHi(){
alert(\"Hi!\");
}
//--></script>
给脚本加上 HTML 注释后,Mosaic 等浏览器就会忽略<script>标签中的内容;而那些支持
JavaScript 的浏览器在遇到这种情况时,则必须进一步确认其中是否包含需要解析的 JavaScript 代码。
虽然这种注释 JavaScript 代码的格式得到了所有浏览器的认可,也能被正确解释,但由于所有浏览
器都已经支持 JavaScript,因此也就没有必要再使用这种格式了。在 XHTML 模式下,因为脚本包含在
XML 注释中,所以脚本会被忽略。
2.2 嵌入代码与外部文件
在 HTML 中嵌入 JavaScript 代码虽然没有问题,但一般认为最好的做法还是尽可能使用外部文件来
包含 JavaScript 代码。不过,并不存在必须使用外部文件的硬性规定,但支持使用外部文件的人多会强
调如下优点。
可维护性:遍及不同 HTML 页面的 JavaScript 会造成维护问题。但把所有 JavaScript 文件都放在
一个文件夹中,维护起来就轻松多了。而且开发人员因此也能够在不触及 HTML 标记的情况下,
集中精力编辑 JavaScript 代码。
可缓存:浏览器能够根据具体的设置缓存链接的所有外部 JavaScript 文件。也就是说,如果有两个
页面都使用同一个文件,那么这个文件只需下载一次。因此,最终结果就是能够加快页面加载的
速度。
适应未来:通过外部文件来包含 JavaScript 无须使用前面提到 XHTML 或注释 hack。HTML 和
XHTML 包含外部文件的语法是相同的。
2.3 文档模式
IE5.5 引入了文档模式的概念,而这个概念是通过使用文档类型(doctype)切换实现的。最初的两
图灵社区会员 StinkBC(StinkBC@gmail.com) 专享 尊重版权
2.3 文档模式 17
1
2
3
4
5
13
6
7
8
9
10
11
12
种文档模式是:混杂模式(quirks mode)①和标准模式(standards mode)。混杂模式会让 IE 的行为与(包
含非标准特性的)IE5 相同,而标准模式则让 IE 的行为更接近标准行为。虽然这两种模式主要影响 CSS
内容的呈现,但在某些情况下也会影响到 JavaScript 的解释执行。本书将在必要时再讨论这些因文档模
式而影响 JavaScript 执行的情况。
在 IE 引入文档模式的概念后,其他浏览器也纷纷效仿。在此之后,IE 又提出一种所谓的准标准模
式(almost standards mode)。这种模式下的浏览器特性有很多都是符合标准的,但也不尽然。不标准的
地方主要体现在处理图片间隙的时候(在表格中使用图片时问题最明显)。
如果在文档开始处没有发现文档类型声明,则所有浏览器都会默认开启混杂模式。但采用混杂模式
不是什么值得推荐的做法,因为不同浏览器在这种模式下的行为差异非常大,如果不使用某些 hack 技
术,跨浏览器的行为根本就没有一致性可言。
对于标准模式,可以通过使用下面任何一种文档类型来开启:
<!-- HTML 4.01 严格型 -->
<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\"
\"http://www.w3.org/TR/html4/strict.dtd\">
<!-- XHTML 1.0 严格型 -->
<!DOCTYPE html PUBLIC
\"-//W3C//DTD XHTML 1.0 Strict//EN\"
\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">
<!-- HTML 5 -->
<!DOCTYPE html>
而对于准标准模式,则可以通过使用过渡型(transitional)或框架集型(frameset)文档类型来触发,
如下所示:
<!-- HTML 4.01 过渡型 -->
<!DOCTYPE HTML PUBLIC
\"-//W3C//DTD HTML 4.01 Transitional//EN\"
\"http://www.w3.org/TR/html4/loose.dtd\">
<!-- HTML 4.01 框架集型 -->
<!DOCTYPE HTML PUBLIC
\"-//W3C//DTD HTML 4.01 Frameset//EN\"
\"http://www.w3.org/TR/html4/frameset.dtd\">
<!-- XHTML 1.0 过渡型 -->
<!DOCTYPE html PUBLIC
\"-//W3C//DTD XHTML 1.0 Transitional//EN\"
\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">
<!-- XHTML 1.0 框架集型 -->
<!DOCTYPE html PUBLIC
\"-//W3C//DTD XHTML 1.0 Frameset//EN\"
\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd\">
准标准模式与标准模式非常接近,它们的差异几乎可以忽略不计。因此,当有人提到“标准模式”
时,有可能是指这两种模式中的任何一种。而且,检测文档模式(本书后面将会讨论)时也不会发现什
么不同。本书后面提到标准模式时,指的是除混杂模式之外的其他模式。
——————————
① 这里 quirks mode 的译法源自 Firefox 3.5.5 中文版。
图灵社区会员 StinkBC(StinkBC@gmail.com) 专享 尊重版权
18 第 2 章 在 HTML 中使用 JavaScript
2.4 <noscript>元素
早期浏览器都面临一个特殊的问题,即当浏览器不支持 JavaScript 时如何让页面平稳地退化。对这
个问题的最终解决方案就是创造一个<noscript>元素,用以在不支持 JavaScript 的浏览器中显示替代
的内容。这个元素可以包含能够出现在文档<body>中的任何 HTML 元素——<script>元素除外。包含
在<noscript>元素中的内容只有在下列情况下才会显示出来:
浏览器不支持脚本;
浏览器支持脚本,但脚本被禁用。
符合上述任何一个条件,浏览器都会显示<noscript>中的内容。而在除此之外的其他情况下,浏
览器不会呈现<noscript>中的内容。
请看下面这个简单的例子:
<html>
<head>
<title>Example HTML Page</title>
<script type=\"text/javascript\" defer=\"defer\" src=\"example1.js\"></script>
<script type=\"text/javascript\" defer=\"defer\" src=\"example2.js\"></script>
</head>
<body>
<noscript>
<p>本页面需要浏览器支持(启用)JavaScript。
</noscript>
</body>
</html>
这个页面会在脚本无效的情况下向用户显示一条消息。而在启用了脚本的浏览器中,用户永远也不
会看到它——尽管它是页面的一部分。
2.5 小结
把 JavaScript 插入到 HTML 页面中要使用<script>元素。使用这个元素可以把 JavaScript 嵌入到
HTML 页面中,让脚本与标记混合在一起;也可以包含外部的 JavaScript 文件。而我们需要注意的地方有:
在包含外部 JavaScript 文件时,必须将 src 属性设置为指向相应文件的 URL。而这个文件既可
以是与包含它的页面位于同一个服务器上的文件,也可以是其他任何域中的文件。
所有<script>元素都会按照它们在页面中出现的先后顺序依次被解析。在不使用 defer 和
async 属性的情况下,只有在解析完前面<script>元素中的代码之后,才会开始解析后面
<script>元素中的代码。
由于浏览器会先解析完不使用 defer 属性的<script>元素中的代码,然后再解析后面的内容,
所以一般应该把<script>元素放在页面最后,即主要内容后面,</body>标签前面。
使用 defer 属性可以让脚本在文档完全呈现之后再执行。延迟脚本总是按照指定它们的顺序执行。
使用 async 属性可以表示当前脚本不必等待其他脚本,也不必阻塞文档呈现。不能保证异步脚
本按照它们在页面中出现的顺序执行。
另外,使用<noscript>元素可以指定在不支持脚本的浏览器中显示的替代内容。但在启用了脚本
的情况下,浏览器不会显示<noscript>元素中的任何内容。
图灵社区会员 StinkBC(StinkBC@gmail.com) 专享 尊重版权
3.1 语法 19
1
2
3
4
5
13
6
7
8
9
10
11
12
基 本 概 念
本章内容
语法
数据类型
流控制语句
函数
何语言的核心都必然会描述这门语言最基本的工作原理。而描述的内容通常都要涉及这门语
言的语法、操作符、数据类型、内置功能等用于构建复杂解决方案的基本概念。如前所述,
ECMA-262 通过叫做 ECMAScript 的“伪语言”为我们描述了 JavaScript 的所有这些基本概念。
目前,ECMA-262 第 3 版中定义的 ECMAScript 是各浏览器实现最多的一个版本。ECMA-262 第 5
版是浏览器接下来实现的版本,但截止到 2011 年底,还没有浏览器完全实现了这个版本。为此,本章
将主要按照第 3 版定义的 ECMAScript 介绍这门语言的基本概念,并就第 5 版的变化给出说明。
3.1 语法
ECMAScript 的语法大量借鉴了 C 及其他类 C 语言(如 Java 和 Perl)的语法。因此,熟悉这些语言
的开发人员在接受 ECMAScript 更加宽松的语法时,一定会有一种轻松自在的感觉。
3.1.1 区分大小写
要理解的第一个概念就是 ECMAScript 中的一切(变量、函数名和操作符)都区分大小写。这也就
意味着,变量名 test 和变量名 Test 分别表示两个不同的变量,而函数名不能使用 typeof,因为它
是一个关键字(3.2 节介绍关键字),但 typeOf 则完全可以是一个有效的函数名。
3.1.2 标识符
所谓标识符,就是指变量、函数、属性的名字,或者函数的参数。标识符可以是按照下列格式规则
组合起来的一或多个字符:
第一个字符必须是一个字母、下划线(_)或一个美元符号($);
其他字符可以是字母、下划线、美元符号或数字。
标识符中的字母也可以包含扩展的 ASCII 或 Unicode 字母字符(如 À 和 Æ),但我们不推荐这样做。
按照惯例,ECMAScript 标识符采用驼峰大小写格式,也就是第一个字母小写,剩下的每个单词的
首字母大写,例如:
任
第 3 章
图灵社区会员 StinkBC(StinkBC@gmail.com) 专享 尊重版权
20 第 3 章 基本概念
firstSecond
myCar
doSomethingImportant
虽然没有谁强制要求必须采用这种格式,但为了与 ECMAScript 内置的函数和对象命名格式保持一
致,可以将其当作一种最佳实践。
不能把关键字、保留字、true、false 和 null 用作标识符。3.2节将介绍更多相
关内容。
3.1.3 注释
ECMAScript 使用 C 风格的注释,包括单行注释和块级注释。单行注释以两个斜杠开头,如下所示:
// 单行注释
块级注释以一个斜杠和一个星号(/*)开头,以一个星号和一个斜杠(*/)结尾,如下所示:
/*
* 这是一个多行
* (块级)注释
*/
虽然上面注释中的第二和第三行都以一个星号开头,但这不是必需的。之所以添加那两个星号,纯
粹是为了提高注释的可读性(这种格式在企业级应用中用得比较多)。
3.1.4 严格模式
ECMAScript 5 引入了严格模式(strict mode)的概念。严格模式是为 JavaScript 定义了一种不同的
解析与执行模型。在严格模式下,ECMAScript 3 中的一些不确定的行为将得到处理,而且对某些不安全
的操作也会抛出错误。要在整个脚本中启用严格模式,可以在顶部添加如下代码:
\"use strict\";
这行代码看起来像是字符串,而且也没有赋值给任何变量,但其实它是一个编译指示(pragma),
用于告诉支持的 JavaScript 引擎切换到严格模式。这是为不破坏 ECMAScript 3 语法而特意选定的语法。
在函数内部的上方包含这条编译指示,也可以指定函数在严格模式下执行:
function doSomething(){
\"use strict\";
//函数体
}
严格模式下,JavaScript 的执行结果会有很大不同,因此本书将会随时指出严格模式下的区别。支
持严格模式的浏览器包括 IE10+、Firefox 4+、Safari 5.1+、Opera 12+和 Chrome。
3.1.5 语句
ECMAScript 中的语句以一个分号结尾;如果省略分号,则由解析器确定语句的结尾,如下例所示:
图灵社区会员 StinkBC(StinkBC@gmail.com) 专享 尊重版权
3.2 关键字和保留字 21
1
2
3
4
5
13
6
7
8
9
10
11
12
var sum = a + b // 即使没有分号也是有效的语句——不推荐
var diff = a - b; // 有效的语句——推荐
虽然语句结尾的分号不是必需的,但我们建议任何时候都不要省略它。因为加上这个分号可以避免
很多错误(例如不完整的输入),开发人员也可以放心地通过删除多余的空格来压缩 ECMAScript 代码(代
码行结尾处没有分号会导致压缩错误)。另外,加上分号也会在某些情况下增进代码的性能,因为这样
解析器就不必再花时间推测应该在哪里插入分号了。
可以使用 C 风格的语法把多条语句组合到一个代码块中,即代码块以左花括号({)开头,以右花
括号(})结尾:
if (test){
test = false;
alert(test);
}
虽然条件控制语句(如 if 语句)只在执行多条语句的情况下才要求使用代码块,但最佳实践是始
终在控制语句中使用代码块——即使代码块中只有一条语句,例如:
if (test)
alert(test); // 有效但容易出错,不要使用
if (test){ // 推荐使用
alert(test);
}
在控制语句中使用代码块可以让编码意图更加清晰,而且也能降低修改代码时出错的几率。
3.2 关键字和保留字
ECMA-262 描述了一组具有特定用途的关键字,这些关键字可用于表示控制语句的开始或结束,或
者用于执行特定操作等。按照规则,关键字也是语言保留的,不能用作标识符。以下就是 ECMAScript
的全部关键字(带*号上标的是第 5 版新增的关键字):
break do instanceof typeof
case else new var
catch finally return void
continue for switch while
debugger* function this with
default if throw
delete in try
ECMA-262 还描述了另外一组不能用作标识符的保留字。尽管保留字在这门语言中还没有任何特定
的用途,但它们有可能在将来被用作关键字。以下是 ECMA-262 第 3 版定义的全部保留字:
abstract enum int short
boolean export interface static
byte extends long super
char final native synchronized
class float package throws
const goto private transient
debugger implements protected volatile
double import public
图灵社区会员 StinkBC(StinkBC@gmail.com) 专享 尊重版权
22 第 3 章 基本概念
第 5 版把在非严格模式下运行时的保留字缩减为下列这些:
class enum extends super
const export import
在严格模式下,第 5 版还对以下保留字施加了限制:
implements package public
interface private static
let protected yield
注意,let 和 yield 是第 5 版新增的保留字;其他保留字都是第 3 版定义的。为了最大程度地保
证兼容性,建议读者将第 3 版定义的保留字外加 let 和 yield 作为编程时的参考。
在实现 ECMAScript 3 的 JavaScript 引擎中使用关键字作标识符,会导致“Identifier Expected”错误。
而使用保留字作标识符可能会也可能不会导致相同的错误,具体取决于特定的引擎。
第 5 版对使用关键字和保留字的规则进行了少许修改。关键字和保留字虽然仍然不能作为标识符使
用,但现在可以用作对象的属性名。一般来说,最好都不要使用关键字和保留字作为标识符和属性名,
以便与将来的 ECMAScript 版本兼容。
除了上面列出的保留字和关键字,ECMA-262 第 5 版对 eval 和 arguments 还施加了限制。在严
格模式下,这两个名字也不能作为标识符或属性名,否则会抛出错误。
3.3 变量
ECMAScript 的变量是松散类型的,所谓松散类型就是可以用来保存任何类型的数据。换句话说,
每个变量仅仅是一个用于保存值的占位符而已。定义变量时要使用 var 操作符(注意 var 是一个关键
字),后跟变量名(即一个标识符),如下所示:
var message;
这行代码定义了一个名为 message 的变量,该变量可以用来保存任何值(像这样未经过初始化的
变量,会保存一个特殊的值——undefined,相关内容将在 3.4 节讨论)。ECMAScript 也支持直接初始
化变量,因此在定义变量的同时就可以设置变量的值,如下所示:
var message = \"hi\";
在此,变量 message 中保存了一个字符串值\"hi\"。像这样初始化变量并不会把它标记为字符串类型;
初始化的过程就是给变量赋一个值那么简单。因此,可以在修改变量值的同时修改值的类型,如下所示:
var message = \"hi\";
message = 100; // 有效,但不推荐
在这个例子中,变量 message 一开始保存了一个字符串值\"hi\",然后该值又被一个数字值 100 取
代。虽然我们不建议修改变量所保存值的类型,但这种操作在 ECMAScript 中完全有效。
有一点必须注意,即用 var 操作符定义的变量将成为定义该变量的作用域中的局部变量。也就是说,
如果在函数中使用 var 定义一个变量,那么这个变量在函数退出后就会被销毁,例如:
function test(){
var message = \"hi\"; // 局部变量
}
test();
alert(message); // 错误!
图灵社区会员 StinkBC(StinkBC@gmail.com) 专享 尊重版权
3.4 数据类型 23
1
2
3
4
5
13
6
7
8
9
10
11
12
这里,变量 message 是在函数中使用 var 定义的。当函数被调用时,就会创建该变量并为其赋值。
而在此之后,这个变量又会立即被销毁,因此例子中的下一行代码就会导致错误。不过,可以像下面这
样省略 var 操作符,从而创建一个全局变量:
function test(){
message = \"hi\"; // 全局变量
}
test();
alert(message); // \"hi\"
这个例子省略了 var 操作符,因而 message 就成了全局变量。这样,只要调用过一次 test()函
数,这个变量就有了定义,就可以在函数外部的任何地方被访问到。
虽然省略 var 操作符可以定义全局变量,但这也不是我们推荐的做法。因为在局
部作用域中定义的全局变量很难维护,而且如果有意地忽略了 var 操作符,也会由于
相应变量不会马上就有定义而导致不必要的混乱。给未经声明的变量赋值在严格模式
下会导致抛出 ReferenceError 错误。
可以使用一条语句定义多个变量,只要像下面这样把每个变量(初始化或不初始化均可)用逗号分
隔开即可:
var message = \"hi\",
found = false,
age = 29;
这个例子定义并初始化了 3 个变量。同样由于 ECMAScript 是松散类型的,因而使用不同类型初始
化变量的操作可以放在一条语句中来完成。虽然代码里的换行和变量缩进不是必需的,但这样做可以提
高可读性。
在严格模式下,不能定义名为 eval 或 arguments 的变量,否则会导致语法错误。
3.4 数据类型
ECMAScript 中有 5 种简单数据类型(也称为基本数据类型):Undefined、Null、Boolean、Number
和 String。还有 1种复杂数据类型——Object,Object 本质上是由一组无序的名值对组成的。ECMAScript
不支持任何创建自定义类型的机制,而所有值最终都将是上述 6 种数据类型之一。乍一看,好像只有 6
种数据类型不足以表示所有数据;但是,由于 ECMAScript 数据类型具有动态性,因此的确没有再定义
其他数据类型的必要了。
3.4.1 typeof操作符
鉴于 ECMAScript 是松散类型的,因此需要有一种手段来检测给定变量的数据类型——typeof 就
是负责提供这方面信息的操作符。对一个值使用 typeof 操作符可能返回下列某个字符串:
\"undefined\"——如果这个值未定义;
\"boolean\"——如果这个值是布尔值;
\"string\"——如果这个值是字符串;
图灵社区会员 StinkBC(StinkBC@gmail.com) 专享 尊重版权
24 第 3 章 基本概念
\"number\"——如果这个值是数值;
\"object\"——如果这个值是对象或 null;
\"function\"——如果这个值是函数。
下面是几个使用 typeof 操作符的例子:
var message = \"some string\";
alert(typeof message); // \"string\"
alert(typeof(message)); // \"string\"
alert(typeof 95); // \"number\"
TypeofExample01.htm
这几个例子说明,typeof 操作符的操作数可以是变量(message),也可以是数值字面量。注意,
typeof 是一个操作符而不是函数,因此例子中的圆括号尽管可以使用,但不是必需的。
有些时候,typeof 操作符会返回一些令人迷惑但技术上却正确的值。比如,调用 typeof null
会返回\"object\",因为特殊值 null 被认为是一个空的对象引用。Safari 5 及之前版本、Chrome 7 及之
前版本在对正则表达式调用 typeof 操作符时会返回\"function\",而其他浏览器在这种情况下会返回
\"object\"。
从技术角度讲,函数在 ECMAScript 中是对象,不是一种数据类型。然而,函数也
确实有一些特殊的属性,因此通过 typeof 操作符来区分函数和其他对象是有必要的。
3.4.2 Undefined类型
Undefined 类型只有一个值,即特殊的 undefined。在使用 var 声明变量但未对其加以初始化时,
这个变量的值就是 undefined,例如:
var message;
alert(message == undefined); //true
UndefinedExample01.htm
这个例子只声明了变量 message,但未对其进行初始化。比较这个变量与 undefined 字面量,结
果表明它们是相等的。这个例子与下面的例子是等价的:
var message = undefined;
alert(message == undefined); //true
UndefinedExample02.htm
这个例子使用 undefined 值显式初始化了变量 message。但我们没有必要这么做,因为未经初始
化的值默认就会取得 undefined 值。
一般而言,不存在需要显式地把一个变量设置为 undefined 值的情况。字面值
undefined 的主要目的是用于比较,而 ECMA-262 第 3 版之前的版本中并没有规定
这个值。第 3 版引入这个值是为了正式区分空对象指针与未经初始化的变量。
图灵社区会员 StinkBC(StinkBC@gmail.com) 专享 尊重版权
3.4 数据类型 25
1
2
3
4
5
13
6
7
8
9
10
11
12
不过,包含 undefined 值的变量与尚未定义的变量还是不一样的。看看下面这个例子:
var message; // 这个变量声明之后默认取得了 undefined 值
// 下面这个变量并没有声明
// var age
alert(message); // \"undefined\"
alert(age); // 产生错误
UndefinedExample03.htm
运行以上代码,第一个警告框会显示变量 message 的值,即\"undefined\"。而第二个警告框——
由于传递给 alert()函数的是尚未声明的变量 age——则会导致一个错误。对于尚未声明过的变量,只
能执行一项操作,即使用 typeof 操作符检测其数据类型(对未经声明的变量调用 delete 不会导致错
误,但这样做没什么实际意义,而且在严格模式下确实会导致错误)。
然而,令人困惑的是:对未初始化的变量执行 typeof 操作符会返回 undefined 值,而对未声明
的变量执行 typeof 操作符同样也会返回 undefined 值。来看下面的例子:
var message; // 这个变量声明之后默认取得了 undefined 值
// 下面这个变量并没有声明
// var age
alert(typeof message); // \"undefined\"
alert(typeof age); // \"undefined\"
UndefinedExample04.htm
结果表明,对未初始化和未声明的变量执行 typeof 操作符都返回了 undefined 值;这个结果有
其逻辑上的合理性。因为虽然这两种变量从技术角度看有本质区别,但实际上无论对哪种变量也不可能
执行真正的操作。
即便未初始化的变量会自动被赋予 undefined 值,但显式地初始化变量依然是
明智的选择。如果能够做到这一点,那么当 typeof 操作符返回\"undefined\"值时,
我们就知道被检测的变量还没有被声明,而不是尚未初始化。
3.4.3 Null类型
Null 类型是第二个只有一个值的数据类型,这个特殊的值是 null。从逻辑角度来看,null 值表
示一个空对象指针,而这也正是使用 typeof 操作符检测 null 值时会返回\"object\"的原因,如下面
的例子所示:
var car = null;
alert(typeof car); // \"object\"
NullExample01.htm
图灵社区会员 StinkBC(StinkBC@gmail.com) 专享 尊重版权
26 第 3 章 基本概念
如果定义的变量准备在将来用于保存对象,那么最好将该变量初始化为 null 而不是其他值。这样
一来,只要直接检查 null 值就可以知道相应的变量是否已经保存了一个对象的引用,如下面的例子
所示:
if (car != null){
// 对 car 对象执行某些操作
}
实际上,undefined 值是派生自 null 值的,因此 ECMA-262 规定对它们的相等性测试要返回 true:
alert(null == undefined); //true
NullExample02.htm
这里,位于 null 和 undefined 之间的相等操作符(==)总是返回 true,不过要注意的是,这个
操作符出于比较的目的会转换其操作数(本章后面将详细介绍相关内容)。
尽管 null 和 undefined 有这样的关系,但它们的用途完全不同。如前所述,无论在什么情况下
都没有必要把一个变量的值显式地设置为 undefined,可是同样的规则对 null 却不适用。换句话说,
只要意在保存对象的变量还没有真正保存对象,就应该明确地让该变量保存 null 值。这样做不仅可以
体现 null 作为空对象指针的惯例,而且也有助于进一步区分 null 和 undefined。
3.4.4 Boolean类型
Boolean 类型是 ECMAScript 中使用得最多的一种类型,该类型只有两个字面值:true 和 false。
这两个值与数字值不是一回事,因此 true 不一定等于 1,而 false 也不一定等于 0。以下是为变量赋
Boolean 类型值的例子:
var found = true;
var lost = false;
需要注意的是,Boolean 类型的字面值 true 和 false 是区分大小写的。也就是说,True 和 False
(以及其他的混合大小写形式)都不是 Boolean 值,只是标识符。
虽然 Boolean 类型的字面值只有两个,但 ECMAScript 中所有类型的值都有与这两个 Boolean 值
等价的值。要将一个值转换为其对应的 Boolean 值,可以调用转型函数 Boolean(),如下例所示:
var message = \"Hello world!\";
var messageAsBoolean = Boolean(message);
BooleanExample01.htm
在这个例子中,字符串 message 被转换成了一个 Boolean 值,该值被保存在 messageAsBoolean
变量中。可以对任何数据类型的值调用 Boolean()函数,而且总会返回一个 Boolean 值。至于返回的
这个值是 true 还是 false,取决于要转换值的数据类型及其实际值。下表给出了各种数据类型及其对
应的转换规则。
数据类型 转换为true的值 转换为false的值
Boolean true false
String 任何非空字符串 \"\"(空字符串)
图灵社区会员 StinkBC(StinkBC@gmail.com) 专享 尊重版权
3.4 数据类型 27
1
2
3
4
5
13
6
7
8
9
10
11
12
(续)
数据类型 转换为true的值 转换为false的值
Number 任何非零数字值(包括无穷大) 0和NaN(参见本章后面有关NaN的内容)
Object 任何对象 null
Undefined n/a①
undefined
这些转换规则对理解流控制语句(如 if 语句)自动执行相应的 Boolean 转换非常重要,请看下面
的代码:
var message = \"Hello world!\";
if (message){
alert(\"Value is true\");
}
BooleanExample02.htm
运行这个示例,就会显示一个警告框,因为字符串 message 被自动转换成了对应的 Boolean 值
(true)。由于存在这种自动执行的 Boolean 转换,因此确切地知道在流控制语句中使用的是什么变量
至关重要。错误地使用一个对象而不是一个 Boolean 值,就有可能彻底改变应用程序的流程。
3.4.5 Number类型
Number 类型应该是 ECMAScript 中最令人关注的数据类型了,这种类型使用 IEEE754 格式来表示
整数和浮点数值(浮点数值在某些语言中也被称为双精度数值)。为支持各种数值类型,ECMA-262 定
义了不同的数值字面量格式。
最基本的数值字面量格式是十进制整数,十进制整数可以像下面这样直接在代码中输入:
var intNum = 55; // 整数
除了以十进制表示外,整数还可以通过八进制(以 8 为基数)或十六进制(以 16 为基数)的字面值
来表示。其中,八进制字面值的第一位必须是零(0),然后是八进制数字序列(0~7)。如果字面值中的
数值超出了范围,那么前导零将被忽略,后面的数值将被当作十进制数值解析。请看下面的例子:
var octalNum1 = 070; // 八进制的 56
var octalNum2 = 079; // 无效的八进制数值——解析为 79
var octalNum3 = 08; // 无效的八进制数值——解析为 8
八进制字面量在严格模式下是无效的,会导致支持的 JavaScript 引擎抛出错误。
十六进制字面值的前两位必须是 0x,后跟任何十六进制数字(0~9 及 A~F)。其中,字母 A~F
可以大写,也可以小写。如下面的例子所示:
var hexNum1 = 0xA; // 十六进制的 10
var hexNum2 = 0x1f; // 十六进制的 31
在进行算术计算时,所有以八进制和十六进制表示的数值最终都将被转换成十进制数值。
——————————
① n/a(或 N/A),是 not applicable 的缩写,意思是“不适用”。
图灵社区会员 StinkBC(StinkBC@gmail.com) 专享 尊重版权
28 第 3 章 基本概念
鉴于 JavaScript 中保存数值的方式,可以保存正零(+0)和负零(0)。正零和
负零被认为相等,但为了读者更好地理解上下文,这里特别做此说明。
1. 浮点数值
所谓浮点数值,就是该数值中必须包含一个小数点,并且小数点后面必须至少有一位数字。虽然小
数点前面可以没有整数,但我们不推荐这种写法。以下是浮点数值的几个例子:
var floatNum1 = 1.1;
var floatNum2 = 0.1;
var floatNum3 = .1; // 有效,但不推荐
由于保存浮点数值需要的内存空间是保存整数值的两倍,因此 ECMAScript 会不失时机地将浮点数值
转换为整数值。显然,如果小数点后面没有跟任何数字,那么这个数值就可以作为整数值来保存。同样
地,如果浮点数值本身表示的就是一个整数(如 1.0),那么该值也会被转换为整数,如下面的例子所示:
var floatNum1 = 1.; // 小数点后面没有数字——解析为 1
var floatNum2 = 10.0; // 整数——解析为 10
对于那些极大或极小的数值,可以用 e 表示法(即科学计数法)表示的浮点数值表示。用 e 表示法
表示的数值等于 e 前面的数值乘以 10 的指数次幂。ECMAScript 中 e 表示法的格式也是如此,即前面是
一个数值(可以是整数也可以是浮点数),中间是一个大写或小写的字母 E,后面是 10 的幂中的指数,
该幂值将用来与前面的数相乘。下面是一个使用 e 表示法表示数值的例子:
var floatNum = 3.125e7; // 等于 31250000
在这个例子中,使用 e 表示法表示的变量 floatNum 的形式虽然简洁,但它的实际值则是 31250000。
在此,e 表示法的实际含义就是“3.125 乘以 107
”。
也可以使用 e 表示法表示极小的数值,如 0.00000000000000003,这个数值可以使用更简洁的 3e17
表示。在默认情况下,ECMASctipt 会将那些小数点后面带有 6 个零以上的浮点数值转换为以 e 表示法
表示的数值(例如,0.0000003 会被转换成 3e7)。
浮点数值的最高精度是 17 位小数,但在进行算术计算时其精确度远远不如整数。例如,0.1 加 0.2
的结果不是 0.3,而是 0.30000000000000004。这个小小的舍入误差会导致无法测试特定的浮点数值。
例如:
if (a + b == 0.3){ // 不要做这样的测试!
alert(\"You got 0.3.\");
}
在这个例子中,我们测试的是两个数的和是不是等于 0.3。如果这两个数是 0.05 和 0.25,或者是 0.15
和 0.15 都不会有问题。而如前所述,如果这两个数是 0.1 和 0.2,那么测试将无法通过。因此,永远不
要测试某个特定的浮点数值。
关于浮点数值计算会产生舍入误差的问题,有一点需要明确:这是使用基于
IEEE754 数值的浮点计算的通病,ECMAScript 并非独此一家;其他使用相同数值格
式的语言也存在这个问题。
图灵社区会员 StinkBC(StinkBC@gmail.com) 专享 尊重版权
3.4 数据类型 29
1
2
3
4
5
13
6
7
8
9
10
11
12
2. 数值范围
由于内存的限制,ECMAScript 并不能保存世界上所有的数值。ECMAScript 能够表示的最小数值保
存在 Number.MIN_VALUE 中——在大多数浏览器中,这个值是 5e-324;能够表示的最大数值保存在
Number.MAX_VALUE 中——在大多数浏览器中,这个值是 1.7976931348623157e+308。如果某次计算的
结果得到了一个超出 JavaScript 数值范围的值,那么这个数值将被自动转换成特殊的 Infinity 值。具
体来说,如果这个数值是负数,则会被转换成-Infinity(负无穷),如果这个数值是正数,则会被转
换成 Infinity(正无穷)。
如上所述,如果某次计算返回了正或负的 Infinity 值,那么该值将无法继续参与下一次的计算,
因为 Infinity 不是能够参与计算的数值。要想确定一个数值是不是有穷的(换句话说,是不是位于最
小和最大的数值之间),可以使用 isFinite()函数。这个函数在参数位于最小与最大数值之间时会返
回 true,如下面的例子所示:
var result = Number.MAX_VALUE + Number.MAX_VALUE;
alert(isFinite(result)); //false
尽管在计算中很少出现某些值超出表示范围的情况,但在执行极小或极大数值的计算时,检测监控
这些值是可能的,也是必需的。
访问 Number.NEGATIVE_INFINITY 和 Number.POSITIVE_INFINITY 也可以
得到负和正 Infinity 的值。可以想见,这两个属性中分别保存着-Infinity 和
Infinity。
3. NaN
NaN,即非数值(Not a Number)是一个特殊的数值,这个数值用于表示一个本来要返回数值的操作数
未返回数值的情况(这样就不会抛出错误了)。例如,在其他编程语言中,任何数值除以 0都会导致错误,
从而停止代码执行。但在 ECMAScript中,任何数值除以 0会返回 NaN①,因此不会影响其他代码的执行。
NaN 本身有两个非同寻常的特点。首先,任何涉及 NaN 的操作(例如 NaN/10)都会返回 NaN,这
个特点在多步计算中有可能导致问题。其次,NaN 与任何值都不相等,包括 NaN 本身。例如,下面的代
码会返回 false:
alert(NaN == NaN); //false
针对 NaN 的这两个特点,ECMAScript 定义了 isNaN()函数。这个函数接受一个参数,该参数可以
是任何类型,而函数会帮我们确定这个参数是否“不是数值”。isNaN()在接收到一个值之后,会尝试
将这个值转换为数值。某些不是数值的值会直接转换为数值,例如字符串\"10\"或 Boolean 值。而任何
不能被转换为数值的值都会导致这个函数返回 true。请看下面的例子:
alert(isNaN(NaN)); //true
alert(isNaN(10)); //false(10 是一个数值)
alert(isNaN(\"10\")); //false(可以被转换成数值 10)
alert(isNaN(\"blue\")); //true(不能转换成数值)
alert(isNaN(true)); //false(可以被转换成数值 1)
NumberExample03.htm
——————————
① 原书如此,但实际上只有 0 除以 0 才会返回 NaN,正数除以 0 返回 Infinity,负数除以 0 返回-Infinity。
图灵社区会员 StinkBC(StinkBC@gmail.com) 专享 尊重版权
30 第 3 章 基本概念
这个例子测试了 5 个不同的值。测试的第一个值是 NaN 本身,结果当然会返回 true。然后分别测
试了数值 10 和字符串\"10\",结果这两个测试都返回了 false,因为前者本身就是数值,而后者可以被
转换成数值。但是,字符串\"blue\"不能被转换成数值,因此函数返回了 true。由于 Boolean 值 true
可以转换成数值 1,因此函数返回 false。
尽管有点儿不可思议,但 isNaN()确实也适用于对象。在基于对象调用 isNaN()
函数时,会首先调用对象的 valueOf()方法,然后确定该方法返回的值是否可以转
换为数值。如果不能,则基于这个返回值再调用 toString()方法,再测试返回值。
而这个过程也是 ECMAScript 中内置函数和操作符的一般执行流程,更详细的内容请
参见 3.5 节。
4. 数值转换
有 3 个函数可以把非数值转换为数值:Number()、parseInt()和 parseFloat()。第一个函数,
即转型函数 Number()可以用于任何数据类型,而另两个函数则专门用于把字符串转换成数值。这 3 个
函数对于同样的输入会有返回不同的结果。
Number()函数的转换规则如下。
如果是 Boolean 值,true 和 false 将分别被转换为 1 和 0。
如果是数字值,只是简单的传入和返回。
如果是 null 值,返回 0。
如果是 undefined,返回 NaN。
如果是字符串,遵循下列规则:
如果字符串中只包含数字(包括前面带正号或负号的情况),则将其转换为十进制数值,即\"1\"
会变成 1,\"123\"会变成 123,而\"011\"会变成 11(注意:前导的零被忽略了);
如果字符串中包含有效的浮点格式,如\"1.1\",则将其转换为对应的浮点数值(同样,也会忽
略前导零);
如果字符串中包含有效的十六进制格式,例如\"0xf\",则将其转换为相同大小的十进制整
数值;
如果字符串是空的(不包含任何字符),则将其转换为 0;
如果字符串中包含除上述格式之外的字符,则将其转换为 NaN。
如果是对象,则调用对象的 valueOf()方法,然后依照前面的规则转换返回的值。如果转换
的结果是 NaN,则调用对象的 toString()方法,然后再次依照前面的规则转换返回的字符
串值。
根据这么多的规则使用 Number()把各种数据类型转换为数值确实有点复杂。下面还是给出几个具
体的例子吧。
var num1 = Number(\"Hello world!\"); //NaN
var num2 = Number(\"\"); //0
var num3 = Number(\"000011\"); //11
var num4 = Number(true); //1
NumberExample04.htm
图灵社区会员 StinkBC(StinkBC@gmail.com) 专享 尊重版权
3.4 数据类型 31
1
2
3
4
5
13
6
7
8
9
10
11
12
首先,字符串\"Hello world!\"会被转换为 NaN,因为其中不包含任何有意义的数字值。空字符串
会被转换为 0。字符串\"000011\"会被转换为 11,因为忽略了其前导的零。最后,true 值被转换为 1。
一元加操作符(3.5.1 节将介绍)的操作与 Number()函数相同。
由于 Number()函数在转换字符串时比较复杂而且不够合理,因此在处理整数的时候更常用的是
parseInt()函数。parseInt()函数在转换字符串时,更多的是看其是否符合数值模式。它会忽略字
符串前面的空格,直至找到第一个非空格字符。如果第一个字符不是数字字符或者负号,parseInt()
就会返回 NaN;也就是说,用 parseInt()转换空字符串会返回 NaN(Number()对空字符返回 0)。如
果第一个字符是数字字符,parseInt()会继续解析第二个字符,直到解析完所有后续字符或者遇到了
一个非数字字符。例如,\"1234blue\"会被转换为 1234,因为\"blue\"会被完全忽略。类似地,\"22.5\"
会被转换为 22,因为小数点并不是有效的数字字符。
如果字符串中的第一个字符是数字字符,parseInt()也能够识别出各种整数格式(即前面讨论的
十进制、八进制和十六进制数)。也就是说,如果字符串以\"0x\"开头且后跟数字字符,就会将其当作一
个十六进制整数;如果字符串以\"0\"开头且后跟数字字符,则会将其当作一个八进制数来解析。
为了更好地理解 parseInt()函数的转换规则,下面给出一些例子:
var num1 = parseInt(\"1234blue\"); // 1234
var num2 = parseInt(\"\"); // NaN
var num3 = parseInt(\"0xA\"); // 10(十六进制数)
var num4 = parseInt(22.5); // 22
var num5 = parseInt(\"070\"); // 56(八进制数)
var num6 = parseInt(\"70\"); // 70(十进制数)
var num7 = parseInt(\"0xf\"); // 15(十六进制数)
NumberExample05.htm
在使用 parseInt()解析像八进制字面量的字符串时,ECMAScript 3 和 5 存在分歧。例如:
//ECMAScript 3 认为是 56(八进制),ECMAScript 5 认为是 70(十进制)
var num = parseInt(\"070\");
在 ECMAScript 3 JavaScript 引擎中,\"070\"被当成八进制字面量,因此转换后的值是十进制的 56。
而在 ECMAScript 5 JavaScript 引擎中,parseInt()已经不具有解析八进制值的能力,因此前导的零会
被认为无效,从而将这个值当成\"70\",结果就得到十进制的 70。在 ECMAScript 5 中,即使是在非严格
模式下也会如此。
为了消除在使用 parseInt()函数时可能导致的上述困惑,可以为这个函数提供第二个参数:转换
时使用的基数(即多少进制)。如果知道要解析的值是十六进制格式的字符串,那么指定基数 16 作为第
二个参数,可以保证得到正确的结果,例如:
var num = parseInt(\"0xAF\", 16); //175
实际上,如果指定了 16 作为第二个参数,字符串可以不带前面的\"0x\",如下所示:
var num1 = parseInt(\"AF\", 16); //175
var num2 = parseInt(\"AF\"); //NaN
NumberExample06.htm
图灵社区会员 StinkBC(StinkBC@gmail.com) 专享 尊重版权
32 第 3 章 基本概念
这个例子中的第一个转换成功了,而第二个则失败了。差别在于第一个转换传入了基数,明确告诉
parseInt()要解析一个十六进制格式的字符串;而第二个转换发现第一个字符不是数字字符,因此就
自动终止了。
指定基数会影响到转换的输出结果。例如:
var num1 = parseInt(\"10\", 2); //2 (按二进制解析)
var num2 = parseInt(\"10\", 8); //8 (按八进制解析)
var num3 = parseInt(\"10\", 10); //10 (按十进制解析)
var num4 = parseInt(\"10\", 16); //16 (按十六进制解析)
NumberExample07.htm
不指定基数意味着让 parseInt()决定如何解析输入的字符串,因此为了避免错误的解析,我们建
议无论在什么情况下都明确指定基数。
多数情况下,我们要解析的都是十进制数值,因此始终将 10 作为第二个参数是
非常必要的。
与 parseInt()函数类似,parseFloat()也是从第一个字符(位置 0)开始解析每个字符。而且
也是一直解析到字符串末尾,或者解析到遇见一个无效的浮点数字字符为止。也就是说,字符串中的第
一个小数点是有效的,而第二个小数点就是无效的了,因此它后面的字符串将被忽略。举例来说,
\"22.34.5\"将会被转换为 22.34。
除了第一个小数点有效之外,parseFloat()与 parseInt()的第二个区别在于它始终都会忽略前导
的零。parseFloat()可以识别前面讨论过的所有浮点数值格式,也包括十进制整数格式。但十六进制格
式的字符串则始终会被转换成 0。由于 parseFloat()只解析十进制值,因此它没有用第二个参数指定基
数的用法。最后还要注意一点:如果字符串包含的是一个可解析为整数的数(没有小数点,或者小数点后
都是零),parseFloat()会返回整数。以下是使用 parseFloat()转换数值的几个典型示例。
var num1 = parseFloat(\"1234blue\"); //1234 (整数)
var num2 = parseFloat(\"0xA\"); //0
var num3 = parseFloat(\"22.5\"); //22.5
var num4 = parseFloat(\"22.34.5\"); //22.34
var num5 = parseFloat(\"0908.5\"); //908.5
var num6 = parseFloat(\"3.125e7\"); //31250000
NumberExample08.htm
3.4.6 String类型
String 类型用于表示由零或多个 16 位 Unicode 字符组成的字符序列,即字符串。字符串可以由双
引号(\")或单引号(')表示,因此下面两种字符串的写法都是有效的:
var firstName = \"Nicholas\";
var lastName = 'Zakas';
与 PHP 中的双引号和单引号会影响对字符串的解释方式不同,ECMAScript 中的这两种语法形式没
有什么区别。用双引号表示的字符串和用单引号表示的字符串完全相同。不过,以双引号开头的字符串
图灵社区会员 StinkBC(StinkBC@gmail.com) 专享 尊重版权