深入理解JavaScript

978-7-115-40260-8
作者: 【美】Axel Rauschmayer(罗彻麦尔)
译者: 王玉林杜欢庄婷婷章子鹏
编辑: 陈冀康

图书目录:

详情

本书针对JavaScript初学者,帮助读者掌握JavaScript开发的精髓。每一章从教授语言的一个主题开始,给出了最佳实践以及解决实际缺陷的指南,然后深入到相关的信息。本书帮助入门的程序员理解基础知识,掌握核心实践,甚至深入了解一些实践方法的优缺点,做到知其然且知其所以然。

图书摘要

版权信息

书名:深入理解JavaScript

ISBN:978-7-115-40260-8

本书由人民邮电出版社发行数字版。版权所有,侵权必究。

您购买的人民邮电出版社电子书仅供您个人使用,未经授权,不得以任何方式复制和传播本书内容。

我们愿意相信读者具有这样的良知和觉悟,与我们共同保护知识产权。

如果购买者有侵权行为,我们可能对该用户实施包括但不限于关闭该帐号等维权措施,并可能追究法律责任。

• 著    [美] Axel Rauschmayer

  译    王玉林  杜 欢  庄婷婷  章子鹏

  责任编辑 陈冀康

• 人民邮电出版社出版发行  北京市丰台区成寿寺路11号

  邮编 100164  电子邮件 315@ptpress.com.cn

  网址 http://www.ptpress.com.cn

• 读者服务热线:(010)81055410

  反盗版热线:(010)81055315


Dr.Axel Rauschmayer 专攻JavaScript和Web开发领域。他在2ality.com写博客,是一名Ecmanauten的讲师,还编辑JavaScript周刊,组织MunichJS用户组。他还时常组织会议讨论讲座。

Axel从1985年开始编程,1995年开始开发Web应用。在1999年,他曾任德国互联网创业组织(后来扩大到国际范围)的技术经理。2006年,他举办了他在Ajax上的第一场讲座。

Axel在编程语言设计上做了广泛的研究,并自JavaScript创建以来持续关注其发展现状及趋势。

本书封面上的动物是巴布亚犀鸟(拟皱盔犀鸟属),一种栖息在印尼东部和新几内亚森林树冠的大鸟。这个物种也被称为布莱斯犀鸟。爱德华•布莱斯(1810~1873),是英国生物学家和孟加拉亚洲学会的博物馆馆长。

雄性犀鸟的外观非同寻常,它们的头部和颈部被红橙色或金黄色羽毛包围,而雌性的头部和颈部则只有黑色的羽毛。雄鸟和雌鸟都有着巨大的黑色身体,反差较大的是它们短白色的尾巴,以及围绕在眼睛和喉咙周围裸露的蓝白色皮肤。犀鸟也有红色的眼睛,而雄鸟的眼睛更为鲜艳。

这个品种的巴布亚犀鸟的鸣叫声一直被报道成是这种鸟发出的笑声。在飞行的时候,它们的翅膀发出响亮而独特的声音,沙沙的声音就如从蒸汽机车里逃逸出来蒸汽的声音。不足为奇,就以其巨大的个头和惊艳的外观来讲,巴布亚犀鸟可谓是一种相当显眼的鸟,经常可以看到其飞过森林,频频发出独特的鸣叫声。

这些令人印象深刻的鸟儿,在它们原住的岛屿被当作食物和战利品而被猎杀,它们的头骨,偶尔也被打磨成装饰品。如同其他的犀鸟一样,它们的饮食主要包括水果,尤其是无花果,偶尔辅以昆虫和其他小动物。

本书特色

本书针对JavaScript初学者,帮助读者掌握JavaScript开发的精髓。每一章从教授语言的一个主题开始,给出了最佳实践以及解决实际缺陷的指南,然后深入到相关的信息。本书帮助入门的程序员理解基础知识,掌握核心实践,甚至深入了解一些实践方法的优缺点,做到知其然且知其所以然。

《JavaScript启示录》一书作者Cody Lindley鼎力推荐


Copyright© 2014 by O’Reilly Media, Inc.

Simplified Chinese Edition, jointly published by O’Reilly Media, Inc. and Posts & Telecom Press, 2015. Authorized translation of the English edition, 2014 O’Reilly Media, Inc., the owner of all rights to publish and sell the same.

All rights reserved including the rights of reproduction in whole or in part in any form.

本书中文简体版由O’Reilly Media, Inc. 授权人民邮电出版社出版。未经出版者书面许可,对本书的任何部分不得以任何方式复制或抄袭。

版权所有,侵权必究。


JavaScript是目前Web开发领域非常流行的一种编程语言,得到众多IT从业人员和编程爱好者的关注。

本书是一本全面、深入介绍JavaScript语言的学习指南。本书共分四个部分,第1部分帮助读者快速入手,掌握基本的JavaScript编程要点;第2部分介绍JavaScript的发展和技术背景;第3部分深入探索JavaScript,介绍了语法、值、运算符、布尔类型、数字、字符串、语句、异常捕获、函数、变量、对象与继承、数组、正则表达式、Date、Math、JSON、标准全局变量、编码和JavaScript、ECMAScript 5的新特性等内容;第4部分介绍技巧、工具和类库,帮助读者更好地运用JavaScript进行编程。

本书内容由浅入深,非常适合想要快速学习JavaScript编程或者深入钻研JavaScript的读者参考。


王玉林

花名:小飞

微博:@非常长

魔筷科技创始人,原阿里巴巴资深前端工程师,原阿里花名“飞长”。喜欢安静地写代码,同时也愿意从商业角度做一点点思考,努力做一些可能很微小,但对这个世界有那么点意义和价值的事。目前魔筷科技正专注于提供完整的移动电商解决方案。

杜欢

花名:风驰

邮箱:fengchi.dh@taobao.com

淘宝高级技术专家,专注Web产品设计、整体架构和可用性实施,热爱标准化。

庄婷婷

花名:紫溪

邮箱:sleep.ztt@gmail.com

阿里前端工程师,在前端开发方面积累了多年经验。闲暇时喜欢旅行、阅读,偶尔翻译点技术文章,不断探寻有趣的事。

章子鹏

花名:乔福

微博:@请强刷五次

一名普通的前端开发工程师,就职于淘宝用户体验部,花名“乔福”。以前的愿望是期望国内的IE6份额不断降低,现在力求利用丰富的Web技术构建优秀的用户体验的产品。在业余时间会做一些翻译,捣鼓前端技术、Linux和Shell等。目前在学习iOS和日语。

淘宝前端学习创新小组、Trans4fun前端翻译小站、魔筷科技前端小组、黄冬林、丁迁迁、陈名杨、林时探、张伟、刘雄、李靖和周婷婷(以上排名不分先后)。


“很大一部分人认为JavaScript是简单的,并且在很多情况下它的确如此。JavaScript的简洁优雅源自它深层的功能,如果你使用得当,你可以将JavaScript发挥到不可思议的程度。作者能够将这一特点深深地体现在一本触手可及的参考书中,这无疑使得有追求、富有经验的JavaScript开发者能够更深入地了解这门语言。”

——Rey Bango

一名对JavaScript充满热爱的程序员

“Axel的写作风格简洁、中肯到位,同时又能将知识进行详细阐述。书中许许多多的代码示例甚至将最复杂的内容都能一一表示清楚。”

——Mathias Bynens

来自比利时的Web标准爱好者

本书是一本很符合当下情况的书,它旨在使现今的JavaScript资深程序员对JavaScript有更深入的学习和了解。作者对于知识点没有做费劲耗时的解释,而是直入主题说明JavaScript最核心的部分以及其他各种理念,使得人们得以快速学习了解这一试图在开发者世界独占鳌头的语言。”

——Peter Cooper

出版商、企业家以及Fluent大会的联合发起者

“如果你喜欢Axel的博客,那么你也会喜欢上这本书。书中包含了丰富的代码示例来加深学习过程。我强烈向你推荐这本书,它能使你更加了解JavaScript的大大小小各方面。”

——Elijah Manor

来自Dave Ramsey的Web前端开发者

“本书通过大量的背景知识和深入的介绍将你领入现代的JavaScript 社区,让你彻头彻尾地了解整个JavaScript社区。”

——Mitch Pronschinske

DZone编辑

“关注了Axel Rauschmayer博士的工作有些年了,我很高兴他将他对于JavaScript的深入了解写成了这本书并将它推向这门语言的初学者。与此前我读过的其他JavaScript相关书籍相比,这本书对JavaScript的叙述更为细致和全面,但绝不会枯燥乏味。我会一直推荐这本书。”

——Guillermo Rauch

演讲者、socket.io和mongoose作者、早期Node.js的贡献者


由于JavaScript在Web开发中的流行以及其他因素,它变得不容忽视。然而,这并不意味着它得到了广泛的喜爱。我希望通过这本书使你相信:即使在使用JavaScript时需要接受一定的怪异模式,它仍然是一种使你能够高效、快乐地进行编程的语言。

尽管从JavaScript诞生以来就一直关注其发展,我仍然花了很长时间去熟悉它。然而,当最终熟悉它时我发现之前的经历已经使我准备充分,因为我之前使用Scheme、Java(包括GWT)、Python、Perl和Self(这些语言都影响了我对JavaScript的学习)。

2010年我开始接触Node.js,它给了我在服务器和客户端均使用JavaScript的希望。最终,我改用JavaScript作为我的主要编程语言。在我学习JavaScript的过程中,我开始写书记录我的发现,就是你们在阅读的这本。我在博客中发表了书中的部分内容和一些关于JavaScript的其他资料。这对我的帮助可以从几个方面来说:积极的反馈鼓励我继续下去并使我在写书时不那么孤单;对博客的批评意见给了我额外的信息和建议,使人们了解我的工作,这最终促成了O’Reilly 出版了这本书。

因此,这本书的编写过程长达三年。我持续修订这本书的内容,这长期的准备阶段使它变得更好。我很高兴最终完成了这本书并希望人们发现它对于学习JavaScript是有用的。O’Reilly允许在线免费阅读,这有利于更多的读者能够看到这本书。

这本书适合你吗?以下内容能帮你确定。

这本书是由一个程序员写给程序员们的。为了理解本书,你应该已经通过主流编程语言了解了面向对象的编程,例如Java、PHP、C++、Python、Ruby、Objective-C、C#或Perl。

本书的目标读者是想要快速、充分地学习JavaScript的程序员,以及希望提高技能或寻找特定章节的程序员。

本书专注于JavaScript语言。例如,本书没有专门介绍Web浏览器编程(DOM、异步编程等),只在第33章涉及相关内容。

本书分为四部分,但是主要的两部分为:

这两部分是完全独立的。你可以把它们看作独立的书:前者更像是引导,后者更像是参考。稍后会对本书结构做更多介绍。

本书讲述ECMAScript 5,这是当前所有现代引擎支持的版本。如果你必须使用老版本的Web浏览器,第25章介绍了哪些功能是ECMAScript 5特有的。

关于学习JavaScript最重要的建议是不要被细节困住。的确,在提到语言时有很多细节,而且本书涵盖了大部分的细节,但是,我将为你展示一个相对简洁的蓝图。

本书分为四个部分。

第1部分 JavaScript快速上手

该部分教你“基础JavaScript”,这是很小的一个JavaScript子集但仍能使你快速上手。这部分是独立的,与其他部分不相互依赖。

第2部分 背景

该部分讲述JavaScript的历史和技术背景:JavaScript是何时、为何以及如何诞生的。它与其他编程语言有何相关?是什么重要步骤使JavaScript走到今天所处的位置。

第3部分 深入JavaScript

该部分更像是一个参考:寻找你感兴趣的话题,深入学习和探索。大量的示例会使学习不那么枯燥。

第4部分 技巧、工具和类库

该部分给出了使用JavaScript的建议:最佳实践、先进的技术和学习资源。还介绍了一些重要的工具和库。

在阅读本书时,你可能希望使用命令行。这使你能够进行交互式编码。最受欢迎的选择有:

Node.js

Node.js带有交互的命令行工具。通过调用shell命令node开始使用。

浏览器

所有的主流浏览器都有控制台,在控制台中输入的JavaScript会运行在当前网页的环境下。如何使用,简单地在线搜索你浏览器的名称和“console”即可。

以下符号适用于全书。

描述语法

问号?用于标志可选的参数。例如:

  

法式引号«»表示代码。你可以将这些元代码看作需要实际代码去填充的空白。例如:

  

印刷体方括号标志可选的语法元素。例如:

  

在JavaScript注释中,有时我会使用反引号区分JavaScript和英语:

  

方法相关

我使用完整路径表示内置方法:

  

例如,Array.prototype.join()是指数组的join()方法;也就是说,JavaScript将Array实例的方法都存储在Array.prototype对象上。其原因参见17.10“第3层:构造函数——实例工厂”。

命令行交互

在我介绍一个新概念时,我通常会通过JavaScript命令行的交互来解释它。示例如下:

  

大于号>后面的文本即是输入,由人工输入。其他的即是JavaScript引擎的输出。另外,我使用console.log()方法打印数据到控制台,尤其是在(非——命令行)源代码中:

  

提示、注解和警告

 

提示:

 该元素表明一个提示或建议。


注解:

 该元素表明一个常规注解。


警告:

 该元素表明一个警告。

虽然你可以将本书作为参考,但有时在网上查询信息更快。我推荐的一个资源是Mozilla Developer Network(MDN)。你可以通过网络搜索在MDN上找到文档。例如,下面的网络搜索能够找到关于数组push()方法的文档:

  

Safari® Books Online是一个按需的数字图书库,它通过书和视频的形式提供从世界领先的技术和商业作家那里获取的专业内容。

技术专家、软件开发者、网站设计者、商业和创意专业人士都使用Safari Books Online,作为他们探索、解决问题、学习和认证培训的资源。

Safari Books Online为组织者、政府机构和个体户提供了一系列的产品组合和价格方案。订阅者可以通过一个可充分搜索的数据库获得成千上万的书籍、培训视频和正式出版的手稿。该数据库来自O’Reilly Media、Prentice Hall Professional、Addison-Wesley Professional、Microsoft Press、Sams、Que、Peachpit Press、Focal Press、Cisco Press、John Wiley & Sons、Syngress、Morgan Kaufmann、IBM Redbooks、Packt、Adobe Press、FT Press、Apress、Manning、New Riders、McGraw-Hill、Jones & Bartlett和Course Technology等出版商。想要获取更多详情,可以在线联系我们。

可以根据以下地址将关于本书的问题和评论邮寄给出版商:

美国:

O’Reilly Media, Inc.

1005 Gravenstein Highway North

Sebastopol, CA 95472

中国:

北京市西城区西直门南大街2号成铭大厦C座807室(100035)

奥莱利技术咨询(北京)有限公司

我们为本书建了一个网页,在上面列出了勘误表、示例和所有附加信息。可以通过http://oreil.ly/speaking-js访问网站。

对本书有任何意见或技术问题均可发送邮件到bookquestions@oreilly.com。

想了解关于本书更多的课程、讨论及消息可以访问网站http://www.oreilly.com

我们的Facebook账号:http://facebook.com/oreilly

我们的Twitter账号:http://twitter.com/oreillymedia

我们的YouTube地址:http://www.youtube.com/oreillymedia

我想要感谢以下这些人,有了他们的帮助我才得以完成本书。

JavaScript入门

以下这些人为我理解JavaScript奠定了基础(按时间顺序):

JavaScript进阶

邮件讨论组的成员

他们的答案帮助我理解JavaScript的设计。我深深地感谢他们的耐心和孜孜不倦。以下4人尤其突出:Brendan Eich、Allen Wirfs-Brock、Mark Miller和David Herman。

我博客的读者

我将书中的一些片段发表在了博客上,并获得了读者大量有用的反馈。他们中的一些人是Ben Alman、Brandon Benvie、Mathias Bynens、Andrea Giammarchi、Matthias Reuter和Rick Waldron。

更多资源已在章节中进行说明。

我非常感谢以下帮我审稿的人,他们提供了重要的反馈和修正:


这部分内容相对独立,是对JavaScript的快速介绍。你不需要参考本书的其他部分就能理解本部分内容,其他的部分也不会依赖本部分。可参考前言中“阅读建议”了解阅读技巧。


本章讲的是“基础JavaScript”,这是我定义的一个JavaScript子集,它力求精简,使大家在学习的时候更有效率。我建议在刚开始学习JavaScript的时候,先用它编程感受一段时间。在进阶前不用什么都学,那可能会令你感到困惑。

本节会对JavaScript做一些简单的背景介绍,让你更清楚它的来龙去脉。

ECMAScript是JavaScript的官方命名。因为Java已经是一个商标(它的原始持有者是Sun,现在是Oracle),所以它不得不准备一个新的名字。如今,一些早前收到过授权的公司,如Mozilla,是允许使用JavaScript这个名字的。使用JavaScript这个名字通常需要遵循以下规则。

JavaScript的创造者Brendan Eich,当时除了自己快速地创造这种语言外没有别的选择(或者说,如果他不够快的话,Netscape公司将采用更糟糕的技术)。他借鉴了各种编程语言,如Java(语法、原始值和对象),Scheme、AWK(第一类函数),Self(原型继承)、Perl和Python(字符串、数组和正则表达式)。

直到ECMAScript 3之前,JavaScript都没有异常处理,这也是为什么它经常会自动转换值和静默失败的原因:它最初不能抛出异常。

一方面,JavaScript有些怪异和功能缺失(比如块作用域、模块、子类支持等)。另一方面,它有许多强大的特性可以弥补这些问题。在其他的语言里,我们学的是语言特性,而在JavaScript中,我们常学的却是模式。

有鉴于此,JavaScript支持函数式编程(高阶函数、内置的map和reduce等)和面向对象编程(对象、继承)的混合编程风格也就不足为奇了。

本节将介绍JavaScript的基本语法原则。

一些语法的示例:

  

注意等于号的两种不同用法。

要理解JavaScript的语法,需要认识它的两大语法类别:语句和表达式。

  

  

JavaScript中有两种方式来实现if-then-else,这可以很好地说明语句和表达式之间的区别。语句的方式:

  

表达式的方式:

  

后面这种方式可以用于函数的参数(而前者不行):

  

总之,在JavaScript中,表达式可以用在所有需要语句的地方。比如:

  

整个这行就是一条语句(所谓的表达式语句),但这个函数调用foo(7, 1)也是一个表达式。

在JavaScript中,分号是可选的。然而,我推荐一直带上它,要不JavaScript会猜错语句的结束位置。详见7.5.3“自动分号插入”。

分号用于结束语句,而不是结束块。有一种情况你会看到分号出现在块之后:函数表达式作为一个表达式时。如果这样的表达式出现在语句的最后,它后面就会跟上一个分号:

  

JavaScript有两种类型的注释:单行注释和多行注释。单行注释由两个斜杠//开始,行终止时结束:

  

多行注释限定在/*和*/之间:

  

JavaScript里的变量在声明后使用:

  

变量声明和赋值可以同时进行:

  

也可以为一个已有变量进行赋值:

  

在JavaScript中还会有复合赋值运算符,如+=。以下两种赋值实际上是相等的:

  

标识符是JavaScript中各种语法的名称。例如,变量的名字就是一个标识符。标识符区分大小写。

大致来讲,标识符的第一个字符可以是任意Unicode字符、美元符($),或者下划线(_)。后面的字符除此之外还可以为任意Unicode数字。因此,以下这些都是合法的标识符:

  

以下标识符为保留字——它们是语法的一部分,不能作为变量名使用(包括函数名和参数名):

  

以下三个标识符不是保留字,但同样需要视为保留字:

  

最后,对一些标准的全局变量名,同样需要避开(参见第23章)。虽然它们用作局部变量时不会破坏什么,但这还是会使你的代码变得令人困惑。

JavaScript有很多值,都是我们预期的编程语言的值:布尔值、数字、字符串、数组等。在JavaScript中所有的值都有属性。每一个属性都有一个key(或者是name)和一个value。可以认为,属性就像是一条记录的字段。通过点(.)操作符可以读取属性:

  

例如,字符串'abc'length这个属性:

  

这段代码也可以写为:

  

点操作符同样可以用于给属性赋值:

  

我们也可以通过点操作符来调用方法:

  

在上面的示例中,我们在值hello上调用了toUpperCase()方法。

JavaScript中,对值的区分有点自由。

这两者之间最主要的区别在于它们的比较方式;每个对象都有唯一的标识且只(严格地)等于自己:

  

相反,所有的原始值,只要编码值相同,则被认为相等:

  

后面两节将更详细地介绍原始值和对象。

以下即为所有的原始值(或简称为primitives)。

原始值具有以下特点。

(1)按值进行比较

内容比较:

  

(2)不可改变

其属性不能被改变、添加或移除:

  

(读取一个未知属性时,总会返回undefined。)

所有的非原始值都是对象。最常见的对象如下。

  

上述对象有两个属性:属性firstName的值是Jane,属性lastName的值是Doe

  

上面的数组有3个元素,可以通过数字索引来访问它们。例如,'apple'的索引是0。

  

对象具有以下特点。

(1)按引用进行比较

比较身份标识;每个值都有各自的身份标识:

  

(2)默认可变

对象属性可以很自由地被改变、添加和移除(参见1.14.1“单一对象”):

  

大多数编程语言都会有一些值去表示丢失的信息。JavaScript有两个类似的“空值”,undefinednull

  

丢失的参数也会是undefined

  

访问不存在的属性,也会得到undefined

  

警告:

 undefinednull没有属性,甚至连toString()这种标准方法都没有。

检查undefined或null

通常,函数允许透过undefinednull来表示缺失的值。可以通过以下显式的检查来做到同样的事情:

  

也可以利用undefinednull都可被视为false这一事实来处理:

  

警告:

 false, 0, NaN, 和 '' 都可被视为false(参见1.5.1“真值与假值”)。

有两种对值进行分类的操作符:typeof主要用于原始值,instanceof用于对象。

typeof用法形如:

  

它的返回值会是一个表示这个值“类型”的字符串。如以下示例:

  

表1.1列出了typeof会得到的所有结果:

表1.1

操作数

结果

undefined

'undefined'

null

object

布尔值

boolean

数字

number

字符串

string

函数

function

所有其他的常规值

object

引擎创建的值

JavaScript引擎可以被允许去创建一些值,且typeof的结果可以返回任意字符串(可以与表中列出的结果都不一样)

typeof null返回object是一个不能去修正的bug,因为这会破坏现有的代码。但这并不表示null是一个对象。

instanceof用法形如:

  

如果value是一个通过Constr构造器创建的对象,则返回true(参见1.14.5“构造函数:对象工厂”)。如以下示例:

  

原始布尔类型包含truefalse两个值。以下运算符会产生布尔值。

在JavaScript中,可以使用任意值来表示布尔值(如作为if语句的条件)。它们都会被解释成truefalse。以下的值会被解释成false

其他所有的值(包括所有的对象)都会被当成true。被解释为false的值可被称为假值,被解释为true的值可被称为真值。Boolean()作为函数调用时,会将传入的参数转换为一个布尔值。可以用它来测试看看一个值是如何被解释的:

  

JavaScript中的二元逻辑运算符是短路的。因为如果第一个运算数就足以确定结果的话,则不会对第二个运算数做评估。例如,以下表达式,其中的foo()函数永远不会被调用:

  

此外,二元逻辑运算符会返回运算数中的一个——可能是一个布尔值,也可能不是。对真假的检查将用于确定返回哪一个。

(1)与(&&

如果第一个运算数是假值,返回它。否则,返回第二个运算数。

  

(2)或(||

如果第一个运算数是真值,返回它。否则,返回第二个运算数。

  

JavaScript有两种类型的相等。

常规相等,更多考虑值是否相等(详细解释参见9.3.2“普通(宽松)相等(==,!=)”),这种方式可以隐藏一些bug。因此,推荐使用严格相等。

JavaScript中所有的数字都是浮点数:

  

也包含一些特殊的数字:

NaN“not a number”

一个错误的值:

  

Infinity

多数情况下也是一个错误的值:

  

Infinity比任何一个数都要大(NaN除外)。同样的,-Infinity比任何一个数都要小(NaN除外)。这使得这两个数字常用来作为默认值(比如,当你需要一个最小值和最大值的时候)。

JavaScript具有如下算术运算符(参见11.8“算术运算符”)。

全局对象Math(参见1.17“Math”)还会以函数的方式提供更多算术运算。

JavaScript也有一些位运算符(如位“与”,参见11.9“位运算符”)。

字符串可以直接通过字符串字面量来创建。这些字面量限定在单引号或双引号之内。反斜杠(\)用于转义字符及产生一些控制字符。如以下示例:

  

可以通过方括号来访问字符串中的单个字符:

  

字符串的length属性可以对字符的个数进行计数:

  

像所有的原始值一样,字符串是不可变的;如果要改变一个已有的字符串,必须创建一个新的才行。

字符串可以通过加号(+)进行连接,如果其中一个运算数是字符串的话,另一个运算数将被转换为字符串:

  

要在多个步骤中连接字符串,可以使用+=运算符:

  

字符串有一些常用的方法(参见12.10“字符串原型方法”)。如以下示例:

  

JavaScript中的条件和循环语句将在接下来的小节介绍。

if语句有一个then从句以及一个可选的else从句,具体的执行取决于布尔条件:

  

推荐始终使用大括号(它们表示零个或多个语句块)。不过如果从句仅有一个单独的语句时可以不必这么做(对forwhile语句同样适用):

  

以下是switch语句,fruit的值会决定要执行哪个case

  

case之后跟的“运算数”可以是任意表达式;在switch里的参数会通过===来进行比较。

for循环有如下格式:

  

初始化会在循环开始前执行。条件会在每次循环迭代之前做检查,如果是false则终止循环。后迭代会在每次循环迭代后执行。

以下示例将在控制台打印出数组arr里的每个元素:

  

while循环语句在条件成立的时候会持续循环:

  

do-while循环语句在条件成立时会持续循环。由于条件跟在代码体之后,所以,这些代码体至少会执行一次:

  

有两条语句适用于所有的循环方式:

可以通过函数声明的方式来定义函数:

  

上面的代码定义了函数add,它有两个参数:param1param2,返回值是这两个参数的和。可以这样去调用这个函数:

  

除此之外,我们还可以通过给变量add赋值为函数表达式的方式来定义add函数:

  

函数表达式会产生一个值,因此可以将函数作为参数直接传递给另外的函数:

  

函数声明具有提升特性——它们的实体会被移动到所在作用域的开始处。这使得我们可以引用后面声明的函数。

  

注意,var声明也具有提升的特性(参见1.13.2“变量的提升特性”),但通过它们执行的赋值却不具备该特性:

  

在JavaScript中,函数的所有参数都可以被自由调用,它会通过arguments变量来使所有参数可用。arguments看起来像个数组,但却不具备数组的方法:

  

我们可以通过以下函数来探知,在JavaScript中,函数参数太多或太少是如何处理的(toArray()函数会在1.10.6“将arguments转换为数组”中出现):

  

额外的参数会被忽略(arguments除外):

  

丢失的参数会得到undefined这个值:

  

以下是一个给参数赋上默认值的通用模式:

  

在标记了(1)的这行,||运算符会在x为真值的时候(非nullundefined等值)返回x,否则,会返回第二个运算数:

  

如果想强制一个参数长度(指定的参数长度),可以通过arguments.length来检查:

  

arguments不是数组,它只是类似于数组(参见17.15.3“类似数组的对象和泛型方法”)。它有length属性,可以通过方括号去访问它的元素。不能移除它的元素,也不能对它调用数组的方法。因此,有时候会需要将它转换成数组,方法如以下函数所示(在17.15.3“类似数组的对象和泛型方法”中会有详细介绍):

  

最常见的捕获异常的方式如下所示(参考第14章):

  

使用try语句包裹关键代码,如果try语句有异常会被抛出那么catch语句就会执行。使用之前的代码:

  

严格模式(参见7.8“严格模式”)激活更多的警告以及使JavaScript变得更干净(非严格模式有时候被叫作“松散模式”)。要切换到严格模式,在JavaScript文件或者<script>标签第一行输入:

  

你也可以在每一个函数中激活严格模式:

  

在JavaScript中,通过在变量前使用var语句声明变量:

  

你可以使用单个var语句声明和初始化多个变量:

  

但是我推荐使用单独声明每一个变量(原因参考26.4.1“语法”)。因此,我会将之前的语句重写为:

  

由于前置的缘故(参考1.13.2“变量的提升特性”),通常它的最佳实践是在一个函数的开始部分声明变量。

一个变量的作用域总是完整的函数(相对于当前块)。例如:

  

我们可以看到变量tmp并不局限于(1)行;直到函数结束它都存在。

所有变量声明都会被提升:声明会被移动到函数的开始处,而赋值则仍然会在原来的位置进行。例如,以下函数中的变量会被认为是在标记为(1)的这行声明的:

  

然而在程序内部,上述函数的执行过程其实是这样的:

  

每个函数都和它周围的变量保持着连接,哪怕它离开被创建时的作用域也是如此。例如:

  

函数从标记为(1)的这行开始被创建,在创建结束后即离开它的上下文环境,但它仍然保持着和start的连接:

  

函数以及它所连接的周围作用域中的变量即为闭包。所以,create Incrementor()的返回其实就是一个闭包。

有时你会想要引入一个新的作用域,例如,防止一个变量变成全局变量。在JavaScript中,不能通过块来做,必须使用函数。不过有一种模式可以将函数当做类似块的方式来使用。这种模式被称作为IIFE(立即调用函数表达式,发音为“iffy”):

  

请务必键入以上示例(注释除外)。IIFE是一个在定义之后就被立即调用的函数表达式。在函数内部,会有一个新的作用域,以防止tmp变成全局变量。更多关于IIFE的细节,参见16.6“通过IIFE引入新的作用域”。

IIFE用例:闭包造成的无意共享

闭包会持续地保持与外部变量的连接,而这有时候并不是你想要的:

  

标记为(1)的这行返回值总是i的当前值,而并非函数被创建时的值。在循环结束之后,i的值为5,所以数组中所有的函数都返回这个数值。如果你想要标记(1)这行的函数获得当前i值的一个快照,那么你可以使用IIFE:

  

本节涵盖了JavaScript两种基础的面向对象机制:单一对象和构造函数(类似其他语言中对象的工厂方法)。

和所有的值一样,对象也具有属性。你可以认为对象是一组属性的集合,事实也是如此,每个属性都是一个(键,值)对。键名都是字符串,而值可以是JavaScript的任意值。

在JavaScript中,可以直接通过对象字面量去创建普通对象:

  

上述对象具有namedescribe两个属性。你可以获取(get)以及设置(set)这些属性:

  

以函数作为值的属性被称为方法,如describe。它们使用this对调用它们的对象进行引用:

  

使用in运算符检查属性是否存在:

  

如果读取一个不存在的属性,会得到undefined。因此,之前的两个检查可以这样执行:

  

使用delete运算符移除属性:

  
  

属性的键名可以是任何字符串。迄今为止,我们见到过对象字面量中的属性名和点运算符后的属性名。然而,只有当它们是标识符的时候才可以这样使用(参见1.3.3“标识符与变量名”)。如果想用其他的字符串作为属性名,则必须将它们用引号引起来,再通过对象字面量和方括号来获取或设置这个属性:

  

方括号可以用来动态计算属性键名:

  

如果对方法进行提取,则会失去与对象的连接。就这个函数而言,它不再是一个方法,this的值也会是undefined(在严格模式下)。

看如下示例,先回到之前的jane对象:

  

我们要从jane对象中提取describe方法,将它赋值给变量func,然后对它进行调用。你会发现,它不能正常运行:

  

处理这个问题的解决方案可以使用bind()方法,所有函数都支持。它会创建一个this总是指向给定值的新函数:

  

所有函数都有其特殊的this变量。如果在方法中有嵌套函数,这可能会不太方便,因为在嵌套函数内部不能访问方法中的this变量。下面这个例子展示了调用forEach并结合一个函数来遍历数组:

  

调用logHiToFriends会产生一个错误:

  

让我们来看看这个问题的两种解决方法。第一种,我们可以将this保存在不同的变量中:

  

第二种,利用forEach的第二个参数,它可以给this指定一个值:

  

函数表达式在JavaScript中通常被当作函数调用中的参数来使用。在这些函数表达式中引用this时要特别小心。

到现在为止,JavaScript对象字面量表现出的那种类似于其他语言中映射表/字典的印象,可能会使你觉得JavaScript对象仅仅是字符串到值的映射。然而,JavaScript对象也支持真正的面向对象:继承。本节不会去完全解释JavaScript的继承是如何工作的,而会展示一种简单的模式让你快速上手。想了解更多详情,请查看第17章。

除了“真正的”函数和方法,函数在JavaScript中还扮演了另外一个角色:如果用new运算符来调用的话,它们将变成构造函数即对象工厂。构造函数就是这样简单地模拟了其他语言的类。按照惯例,构造函数的名称以大写字母开头。例如:

  

可以看到构造函数包含两部分。第一部分,Point函数设置实例数据。第二部分,Point.prototype属性包含一个带有方法的对象。第一部分里的实例数据是特定于每一个实例的,而之后的方法数据则是对所有实例共享的。

可以通过new运算符来使用Point

  

pPoint的一个实例:

  

数组是一些有序的元素,可以通过证书索引从0开始被访问。

数组字面量可以方便地创建数组元素:

  

前面的数组有三个元素:字符串abc。你可以通过整数索引来访问它们:

  

length属性表明数组有多少元素。你可以通过使用它来添加或者删除元素:

  

in操作符也可以在数组中正常使用:

  

注意数组是对象,所以可以拥有对象属性:

  

数组拥有许多方法(参见18.7“数组原型方法”)。这里有一些例子:

  

  

有几种数组方法可以用来迭代元素(参见18.12“迭代(非破坏性)”)。其中两种最重要的方法是forEach以及map

forEach迭代数组并且将当前的元素和元素的index扔到一个函数中:

  

前面的代码将输出下面的内容:

  

(1)处的函数可以被随意地忽略参数。例如,它可以只包含一个elem参数。

map通过应用一个函数映射到现有的数组的每个已经存在的元素创建一个新的数组:

  

JavaScript内置的支持正则表达式(第19章引用教程详细地阐述了它是如何工作的)。它们使用斜线分割:

  

  

  

返回的数组包含完整的匹配结果,它的索引从0开始,第一组被捕获的内容的索引是1,以此类推。有一种方法(详见19.6“RegExp.prototype.exec: 捕获分组”)可调用这个方法反复匹配所有内容。

  

replace的第一个参数必须是一个带着/g标志的正则表达式;否则将只替换第一次出现的内容。还有一种方法(详见19.8“Srting.prototype.replace:查找和替换”)可使用一个函数来完成替换。

Math(参见第21章)是一个包含运算功能的对象。示例如下:

  

  

JavaScript的标准库相对简陋,但是有许多我们可以使用的:

Date(第20章)

一个日期构造器,主要功能是解析和创建日期字符串和访问组件的日期(年、小时等)。

JSON&lt(第22章)

一个可以解析和生成JSON数据的对象。

console.*系列方法(参考23.5“ConsoleAPI”)

这些浏览器特定的方法不是这个语言的一部分,但是有一些同样可以运行在Node.js中。


这个部分介绍了JavaScript的历史和本质,针对这种语言给出一个宽泛的前瞻视角以及介绍了它所处的上下文环境(没有太多地深入到技术细节)。

这部分的内容可以选择阅读,即使没有看过,也不影响对本书后面内容的理解。


现在已经有许多种编程语言了,为什么还要用JavaScript呢?本章提到的7个方面在如何选择一门编程语言及如何评判JavaScript整体表现是否良好时都很重要:

1.它能自由使用吗?

2.它是一门优雅的编程语言吗?

3.它真实有用吗?

4.它是否有不错的工具,尤其是很好的集成开发环境(IDE)?

5.它在处理你要做的事情时够快吗?

6.它被广泛使用吗?

7.它有前途吗?

JavaScript可以说是最开放的编程语言:ECMA-262,JavaScript语言的规范,它是一个ISO标准,有着许多独立的实现,其中一些是开源的。此外,该语言是由TC39演变而来,TC39是一个由几家公司组成的委员会,包括所有主要的浏览器厂商。这些公司通常都是竞争对手,但是却能为JavaScript语言的福祉而一起工作。

这很难说,我使用过几种语言,写过许多不同范式的等价代码。因此,我很清楚JavaScript并非那么极致的优雅。然而,它是一种非常灵活的语言,拥有一颗相当优雅的内核,并且能够让你使用面向对象和函数式编程的混合方式。

JavaScript引擎之间的语言兼容性往往会是一个问题,但如今不再是了,这一定程度上要感谢test262套件(https://github.com/tc39/test262),它可以用于检查引擎是否遵循ECMAScript规范。相反,浏览器和DOM的差异仍然是一个挑战。这也是为什么我们通常会借助于框架来隐藏这些差异的原因。

如果它不能让你写出你想要的程序,那么哪怕它是世界上最漂亮的程序语言都没有任何用处。

在图形用户界面方面,JavaScript受益于它已成为HTML5的一部分。在本节中,我用HTML5这个术语来表示“跨浏览器平台”(HTML、CSS,以及浏览器JavaScript API)。HTML5现被广泛部署并且仍在不断地进步,它正逐渐变成完善的一层,能够写出功能完备的、跨浏览器的应用;类似于Java平台,它就像是一个嵌入式的操作系统。HTML5的一个卖点是允许你编写跨平台的图形用户界面。当然,这总会有一些妥协:通过放弃一定的质量要求换取不仅限于单一的操作系统。在过去,“跨平台”意味着Windows、Mac OS,或者Linux。但是现在我们又有了两个交互平台:Web以及mobile。通过HTML5,你可以通过使用诸如PhoneGap、Chrome Apps(http://developer.chrome.com/apps/)、以及TideSDK(http://www.tidesdk.org/)等这些技术去触及所有的平台。

另外,有些平台拥有和原生应用一样的Web应用,或者可以让你将它们安装到本地,例如Chrome OS、Firefox OS以及Android。

有更多不是HTML5的技术对JavaScript进行着有效的补充,使得该语言变得更为实用:

(1)类库

JavaScript有大量的类库,从解析JavaScript(通过Esprima(http://esprima.org)到处理和显示PDF文件(通过PDF.js(https://github.com/mozilla/pdf.js)等,足以让你完成任务。

(2)Node.js(http://nodejs.org

Node.js平台允许你编写服务端代码以及Shell脚本(如构建工具、测试执行等)。

(3)JSON (JavaScript对象表示法, 参见第22章

JSON是一种基于JavaScript的数据格式,已经成为网络上流行的数据交换格式(如Web服务的结果)。

(4)NoSQL数据库 (诸如CouchDB[http://couchdb.apache.org]以及MongoDB [http://www.mongodb.org])

这些数据库和JSON以及JavaScript紧密相连。

JavaScript正在具备越来越好的构建工具(如Grunt[http://gruntjs.com])和测试工具(如mocha[http://visionmedia.github.io/mocha/])。Node.js使得我们可以通过Shell(不仅仅是通过浏览器)来运行这些工具。这一领域存在一个风险就是碎片化,现在正日渐出现太多类似的工具。

JavaScript IDE的空间仍处于较为初级的阶段,但是发展迅速。Web开发的复杂性和活力为它带来创新的沃土。两个开源的例子是Brackets(http://brackets.io)和Light Table(http://www. lighttable.com)。

此外,浏览器也越来越具备开发的环境。如Chrome,尤其是在最近取得了令人印象深刻的进步。看着许多IDE和浏览器未来将整合在一起,这将非常有趣。

JavaScript引擎已经取得了极大的进步,旧的编译器进化成了实时的编译器。绝大多数的应用程序现在已经运行得足够快了。况且,新的想法也正在开发中,它们都为了让未来应用里的JavaScript程序可以执行得足够快:

一门被广泛使用的语言通常有两个好处。首先,这门语言有更好的文档和支持。其次,越来越多的程序员了解它,这点非常重要,不论你是想要雇用别人还是销售基于这门语言的工具。

JavaScript被广泛使用,且获得了以下两个好处。

有几件事表明JavaScript有一个光明的未来。

综上所述,JavaScript做得非常好。当然它不是完美的,但是此时此刻,它很难被击败,并且会做得更好。


相关图书

深入浅出Spring Boot 3.x
深入浅出Spring Boot 3.x
JavaScript核心原理:规范、逻辑与设计
JavaScript核心原理:规范、逻辑与设计
JavaScript入门经典(第7版)
JavaScript入门经典(第7版)
JavaScript函数式编程指南
JavaScript函数式编程指南
PHP、MySQL和JavaScript入门经典(第6版)
PHP、MySQL和JavaScript入门经典(第6版)
JavaScript学习指南(第3版)
JavaScript学习指南(第3版)

相关文章

相关课程