JavaScript面向对象编程指南(第2版)(txt+pdf+epub+mobi电子书下载)


发布时间:2020-06-05 21:42:10

点击下载

作者:[加拿大] Stoyan Stefanov,[印]Kumar Chetan Sharma

出版社:信息技术第一出版分社

格式: AZW3, DOCX, EPUB, MOBI, PDF, TXT

JavaScript面向对象编程指南(第2版)

JavaScript面向对象编程指南(第2版)试读:

前言

本书是《JavaScript面向对象编程指南》的第二版。前一版由Stoyan Stefanov 著(Packet出版社发行),在业界广受好评。然而,自第一版发行至今已过了五个年头。期间,JavaScript由一项主要适用于浏览器客户端的计算机技术,逐渐发展成为一种多功能的程序设计语言,甚至连服务端也能由它来编写。所以在这一版中,我们继续带领大家学习JavaScript的“语言部分”,即其重心依然会放在 JavaScript 语言本身(独立于运行环境部分),着重讨论ECMAScript、JavaScript面向对象编程、模式,原型继承以及设计模式。

本书不会对读者的JavaScript基础知识及项目经验做任何假设。您完全可以从零开始,从本书学习这门语言。同时,对 JavaScript 有一定基础的读者也可以从中学到更多有用的知识。另外,我们在每一章的末尾都设有习题,以便帮助读者了解自己的学习进度。

本书所涵盖的内容

■第1章:面向对象的JavaScript 简单阐述了JavaScript 这门语言的历史、现状及未来。另外,我们还对面向对象程序设计中的基础概念做了一些介绍,并详细说明了该语言调试环境(Firebug)的安装、设置及应用示范。

■第2章:基本数据类型、数组、循环及条件表达式讨论语言中的一些基础性话题,包括变量、数据类型、数组、循环以及条件表达式。

■第3章:函数讨论的是 JavaScript 中函数的使用方法。在这一章中,我们将系统地学习关于函数的一切内容。另外,我们还会了解变量作用域以及内建函数的相关内容。其中有一个叫做“闭包”的概念非常有趣,但也很不容易理解,在该章末尾,我们会重点介绍。

■第4章:对象介绍的是 JavaScript 中的对象类型。在这一章中,我们将学习如何使用对象的属性与方法,以及创建对象的各种方式。另外,我们还会讨论JavaScript中的内建对象,例如Array、Function、Boolean、Number、String等。

■第5章:原型介绍 JavaScript 中有关原型的所有重要概念。包括原型链的工作方式、hasOwnProperty()方法,以及JavaScript中的原型陷阱等。

■第6章:继承讨论如何在JavaScript中实现继承。该章会探讨在JavaScript中创建子类的一种方式,就像那些基于类的面向对象编程语言一样。

■第7章:浏览器环境介绍浏览器相关的内容。在这一章中,我们将会了解到有关BOM(Browser Object Model,浏览器对象模型)和DOM(W3C 的Document Object Model,文档对象模型)的知识,并进一步了解与浏览器事件和AJAX 相关的内容。

■第8章:编程模式与设计模式归纳性地介绍几种专用于 JavaScript 的编程模式,以及若干个与语言无关但适用于JavaScript的设计模式。这些模式大部分来自《设计模式》(GoF)这本书。另外,该章也会对JSON有所讨论。

■附录A:保留字列出了JavaScript中的保留字。

■附录B:内建函数是一份JavaScript中内建函数的参考指南,并附有简单的使用范例。

■附录C:内建对象是一份JavaScript中内建对象类型的参考指南,它提供了详细的对象方法、属性介绍和使用示例。

■附录D:正则表达式是一份正则表达式模式的参考指南。

您可以从下面这个链接获取参考答案的电子版:http://www.packtpub.com/sites/default/files/downloads/3127OT_Answers_to_Exercise_Questions.pdf。

前期准备

在阅读本书之前,您需要安装一个现代浏览器——推荐Google Chrome或者Firefox,并可自由选择是否安装Node.js。虽然最新版本的Firefox自带了Web开发者工具,但我们还是非常推荐您使用Firebug插件。当然,您可以自行选择用于编写JavaScript代码的文本编辑器。

适用对象

本书适用于任何希望学习JavaScript的编程初学者,包括那些懂一点JavaScript,却对其面向对象特性不甚了解的读者。

一些约定

在这本书中,读者会发现几种不同样式的文本,它们各自代表了不同类型的信息。下面,我们将通过一些文本实例来解释一下这些样式各自所代表的含义。

对于一段文本中的代码,我们将以如下形式来表现:“你可以通过检查事件对象的cancellable属性来确认”。

而对于代码块文本,我们将采用如下格式:

var a;

var thisIsAVariable;

var _and_this_too;

var mix12three;

当需要提醒你注意代码的输出时,我们会将相关行或项目的字体加粗,例如:

> var case_matters = 'lower';

> var CASE_MATTERS = 'upper';

> case_matters;

"lower"

> CASE_MATTERS;

"upper"

命令行输入及输出会仿照如下格式呈现:

aliasjsc='/System/Library/Frameworks/JavaScriptCore.framework/Versions/Cu rrent/Resources/jsc'

另外,加粗字体还经常用于强调新的术语或重要词汇。例如,我们屏幕上的菜单以及对话框中会看到的单词,通常会这样表述:“在单击Cancel按钮后,preventDefault()方法就会被调用”。

读者反馈

我们始终欢迎任何来自读者的反馈信息。请务必让我们了解您对于这本书的看法——您喜欢本书的哪部分,或者不喜欢本书的哪部分。这些反馈对于我们的选题开发来说都是至关重要的。

对于一般的反馈,您只需简单地给 feedback@packtpub.com 发一份电子邮件,并在邮件的标题中注明这本书的书名即可。

如果您对某一话题有专长,并且有兴趣撰写一本这方面的书(或为某本书作出贡献),请参考我们的作者指南:http://www.packtpub.com/authors。

客户支持

很荣幸您成为这本 Packt 图书的主人,我们将会尽一切努力来帮助您获取最好的图书资讯。

勘误表

尽管我们已经尽了最大努力来确保书中内容的正确性,但错误始终可能存在。如果您在我们的书中发现了错误——无论是关于文字的还是代码的——只要您能告诉我们,我们都将不胜感激。这样也可以大大减少其他读者在阅读方面所遇到的困难。当您发现错误时,只需要访问http://www.packtpub.com/submit-errata,选择相应的书名,然后单击“errata submission form”链接并输入相关错误的详细信息即可。一旦您提供的信息获得了确认,相关的内容就会出现在这本书的勘误表中。我们出版社所有现存的勘误表都可以在http://www.packtpub.com/support中获取。

版权

在互联网上,版权对于所有媒介一直是一个很大的问题。在Packet,我们向来对于版权许可非常重视。如果您在网络上发现我们出版过的作品,无论它是出于什么形式,都请马上将网址或网站名称告知我们,以便于我们采取补救措施。

请将您怀疑有侵权行为的文档链接发送到:copyright@packetpub.com。您付出的帮助是对作者权利的保护,我们也由此才能继续为您带来有价值的内容。

疑问

如果您对本书有任何疑问,也可以通过 questions@packtpub.com 跟我们联系,我们将竭尽所能地替您解决。第1章面向对象的JavaScript

自 Web 诞生以来,人们对于动态与响应式页面的需求便与日俱增。虽然静态的HTML文本页面在可读性方面或许会更好一些,特别是在有了CSS的辅助之后,页面排版显得更加美观了,但从另一方面来说,如果我们能让人们像在桌面上那样使用浏览器中的应用程序,事情或许会变得更有趣一些。如今,我们已能在浏览器中直接使用电子邮件、日历、电子银行、购物、绘画、游戏及文本编辑。这都要感谢一种Web编程语言——JavaScript,是它让这些Web应用成为了可能。然而,JavaScript最初也只不过是我们偶尔嵌入在HTML中的一小行代码,但如今它已经日趋成熟,并且被广泛使用。开发者们利用该编程语言的面向对象特性,实现了代码重用,并构建起了可伸缩的代码架构。

如果我们回顾一下Web开发领域这些年来的流行词汇——DHTML、Ajax、Web 2.0、HTML5,就会发现这些词背后的内涵始终没有变,依然是:HTML、CSS、JavaScript。其中HTML服务于内容,CSS服务于表现,而JavaScript则服务于行为。换句话说,JavaScript是让一切东西协同运作的粘合剂,有了它,我们才能在构建出丰富多彩的Web应用程序。

但事情远不止如此,JavaScript的应用领域并不仅仅局限于Web平台。

在 JavaScript 程序所能运行的多种宿主环境中,Web 浏览器无疑是用得最普遍的那一种,但JavaScript也可以运行于其他环境。JavaScript可以应用于各式各样的小工具、应用扩展、以及其他软件,本书在后续章节中会一一提及。总而言之,将时间投资于学习JavaScript 是一个明智的选择,因为一旦您掌握了 JavaScript,就可以编写出各种适用于多种平台的不同应用,包括手机应用和服务器端程序。毕竟,如今我们要说 JavaScript 无所不在,那确实是一点都不夸张。

本书将从零开始,我们不会对读者的编程背景做任何假设,只需要您了解一点HTML常识即可。而且除了有一个章节用于探讨Web浏览器环境以外,本书其他部分都在纯粹地关注JavaScript语言本身。因此,您可以将在本书中学到的知识应用于所有的JavaScript环境。

下面,我们将从以下两点开始:

对JavaScript背后故事的简单介绍;

面向对象。1.1回顾历史

起初,Web页面不过是一些以静态HTML文档形式发布的科学出版物,这些文档之间只依靠一些简单的超链接(hyperlinks)绑定在一起。这可能有些难以置信,但最早的Web页面的确是不支持任何图片的,但这种情况不久便得到了改善。随后Web就越来越广受欢迎,规模也在不断增大,很快随着Web业务的快速普及和增长,网站管理者越来越希望自己所创建的Web页面能处理更多的事情。例如,他们希望网站能具有更丰富的用户交互能力,主要是能完成一些简单任务(如验证表单之类),以此节省与服务器端的信息交互。当时他们可以有两种选择:Java applets 和LiveScript。其中,LiveScript是1995年由Netscape公司的 Brendan Eich 所开发的程序设计语言。Netscape 2.0 发布之后,它被正式更名为JavaScript。

众所周知,Applets后来没落了,JavaScript则更加繁荣。这种通过在HTML中嵌入简短代码段来调整Web页面中其他静态元素的方式在网站管理者间大受好评。但没过多久,浏览器的竞争厂商Microsoft 公司就发布了支持JScript的Internet Explorer(IE)3.0。JScript简直就是JavaScript的翻版,并且还在其继承之上引入了一些IE独有的特性。最终,为了使语言的实现更趋向于标准化,于是 ECMAScript 应运而生了。ECMA(欧洲计算机制造商协会)创建了ECMA-262标准,该标准脱离了浏览器和那些Web独有的特性,集中描述了JavaScript作为编程语言的核心部分。

大致上,JavaScript这个术语通常涵盖了以下3个部分。

ECMAScript——语言的核心部分(即变量,函数,循环等等):这个部分独立于浏览器之外,并可以在其他环境中使用。

文档对象模型(DOM):它实际上是提供了一种与 HTML、XML 文档交互的方式。最初,JavaScript 只能提供对页面上一部分元素的有限访问能力,主要集中在表单,超链接和图片这些元素上。后来权限逐渐被扩大,如今几乎所有元素都已经可以访问了。为此,万维网联盟(W3C)还专门创建了DOM标准。该标准是一种独立的(即它并不依赖于JavaScript)操作结构化文档的方式。

浏览器对象模型(BOM):这实际上是一个与浏览器环境有关的对象集合。原本没有任何标准可言,直到HTML5诞生之后,人们才定义了一些浏览器之间通用的对象标准。

虽然本书专门有一个章节用于阐述浏览器、DOM及BOM,但大部分内容还都在讲述JavaScript 语言的核心部分,您在这里所学到的 JavaScript 知识基本都可应用于任何JavaScript执行环境。1.2浏览器的战争与复兴

无论结果是好是坏,JavaScript都在随后爆发的第一次浏览器大战(大约是在1996年到 2001 年间)中得到了迅速的普及。那时正值互联网发展处于第一波热潮,其中主要由Netscape和Microsoft这两大浏览器厂商在争夺市场份额。在此过程中,他们不断地把各种浮华的特性添加到各自的浏览器与JavaScript、DOM及BOM中,从而导致了许多不一致性。与此同时,由于浏览器厂商都在忙于继续增加新的浏览器特性,以至于根本没能及时更新相应的工具,这造成了开发工具的严重滞后。这种情况给使用 JavaScript 的开发人员带来巨大的痛苦。我们将某个浏览器里编写与测试过的脚本在另一个浏览器里测试,却发现脚本不能正常工作,而且还没有合适的错误信息,只得到如“操作终止”之类天书般的错误先知。

实现上的不一致,文档的缺乏,甚至连能将 JavaScript 关键字高亮显示的编辑器都没有。这一切都令开发者们再也没法忍受了。

在另一方面,开发者自己也在他们的Web页面中使用了太多的新特性,总迫不及待地想引入浏览器提供的每一项新功能,以“加强”自己的页面。例如状态栏中的动画、闪烁的颜色、闪烁的文本、会摇晃的浏览器窗口、屏幕上的雪花效果、能跟踪对象的鼠标光标等,这不但牺牲了实用性,而且也伤害了用户体验。这些滥用现象如今大多都消失了,但这在当时极大地损坏了JavaScript在业界的名声。许多“专业的”程序员将JavaScript贬低为设计师的玩具,并批评它不适合用来开发专业应用。JavaScript 语言在一些 Web 项目中遭到了强烈抵制。某些项目甚至完全拒绝对浏览器端进行任何的程序设计,转而只信任他们自己可以掌控的服务器端。确实,在当时那种情况下,也没有什么理由值得我们花费双倍的时间来为这些不同的浏览器设计项目,然后再花更多的时间去调试它们。

这种情况一直持续到第一次浏览器大战结束。但在随后的几年中,Web开发领域在一系列历史进程的推动下,终于发生了一些非常积极的变化。

Microsoft 公司依靠新发布的 IE6 赢得了战争。在那时,IE6 虽然的确是最棒的浏览器,但其后数年,他们却停止了对IE的开发,这给了其他浏览器充分的时间,使它们能够在功能上逐步完成对IE的追赶和超越。

Web 标准化运动渐渐被开发人员和浏览器厂商所接受。这是很自然的,毕竟对于开发人员来说,谁也不想因为不同的浏览器而花费双倍(甚至更多)的开发时间,这促使各方都越来越倾向于遵守统一的开发标准。

开发人员和技术本身也日趋成熟了,越来越多的人开始将注意力转移到其他方面,例如可用性、渐进增强技术及可访问性。开发辅助工具(例如Firebug)也让开发变得更高效,减轻了开发者的负担。

在这种健康环境的影响下,开发人员开始谋求一种更好的新型开发模式,以取代这些现有的开发方式。随着Gmail和Google Maps这一类富客户端应用的相继出现,很显然,如今的JavaScript 已经成为一种成熟的、某些方面独一无二的、拥有强大原型体系的面向对象语言。关于这点,最好的例子莫过于是对XMLHttpRequest对象的重新发现和推广,该对象起初不过是一个IE-only特性,但如今已经得到绝大多数浏览器的支持。通过XMLHttpRequest对象,JavaScript 就能以 HTTP 请求的形式从服务器上获取所需的新鲜内容,从而实现了页面的局部更新。这样一来,我们就不必每次都刷新整个页面。随着XMLHttpRequest对象的广泛应用,一种类桌面式的Web应用模式诞生了,我们称之为AJAX应用。1.3分析现状

有意思的是,JavaScript 必须运行于某种宿主环境中。Web 浏览器仅仅是其中一种, JavaScript 也完全可以运行在服务器端、桌面以及移动设备中。如今,我们已经可以用JavaScript来实现以下功能。

创建拥有强大而丰富功能的 Web 应用程序(这种应用程序往往运行在 Web 浏览器中)。另外还有基于HTML5的许多特性,例如应用缓存、本地存储、本地数据库。无论是线上应用还是离线应用,Web应用都可以做得非常强大。

使用.NET 和 Node.js 编写服务器端脚本,或者使用 Rhino(这是一种用 Java 实现的JavaScript引擎)这样的框架来进行编程。

为移动设备编写各种应用程序。借助于 PhoneGap 及 Titanium 这样的工具,我们完全可以使用纯JavaScript来编写iPhone、Android或其他平台上应用程序。另外值得一提的是,移动平台 Firefox OS 的原生编程语言就是 JavaScript、HTML 和CSS。

使用 ActionScript 创建富媒体应用(如 Flash、Flex)。ActionScript 也是一种基于ECMAScript标准的脚本语言。

编写各种基于命令行的、用于桌面自动化管理的脚本任务。其自带的宿主环境如Windows Scripting Host 及Mac 下的WebKit JavaScript Core。

为一些桌面应用程序编写扩展或插件,例如Dreamweaver、Photoshop 及大多数浏览器。

使用Mozilla XUIRunner及Adobe Air创建跨操作系统的桌面应用程序。

使用Yahoo! Widgets及Mac Dashboard Widgets等工具包来创建桌面小工具。其中, Yahoo! Widgets还可以在智能电视上运行。

当然,这里列出的远远不是该语言的全部应用。JavaScript应用的确发端于Web页面,但如今几乎可以说是无所不在了。另外,浏览器厂商如今都将运行速度视为产品的竞争优势之一,因此都致力于创建更快的 JavaScript 引擎。这对于用户与开发者来说无疑是个好消息,并且这将打开一扇大门——在新的领域,例如在图像、音频及视频处理、游戏开发等方面,JavaScript也必将一展拳脚。1.4展望未来

对于未来的情况,我们这里只能做一些猜测。但几乎可以肯定地说,JavaScript语言必将会有它的一席之地。毕竟,在过去相当长的一段时间里,JavaScript在被严重低估、始终未得到充分利用(或者被错误地滥用了)的情况下,依然几乎每天都能有很多新的、有趣的JavaScript应用被开发出来。一切都是从那行简单的、内嵌于HTML标签中(例如onclick事件)的代码开始的。如今的开发人员所面对的商业开发往往要复杂得多,这需要良好的设计和规划,以及合适的应用扩展和程序库。JavaScript必将在其中得到真正的用武之地,开发人员无疑会更加重视它独有的面向对象特性,以获取越来越多的便利。

曾经被列为职位要求中的“加分项”的 JavaScript,如今已经成为了招聘 Web 开发人员的决定性因素。例如,我们在面试时常会被问到这样的问题:“JavaScript 是一种面向对象语言吗?如果是,JavaScript中的继承关系是如何实现的呢?”在读过这本书之后,您就会对这类面试有充分的准备,甚至还能凭借一些连面试官自己都不知道的知识来打动他们。1.5ECMAScript 5

几乎所有的现代浏览器与其他相关环境都实现了ECMAScript的第3版,对此我们可以安心使用。第4版则直接被跳过了。而ECMAScript的第5版(以下简称为ES5)则到2009年12月才被正式采纳。

ES5 中除了引入了一些新的对象与属性外,它还提供了“严格模式(strict mode)”。所谓严格模式其实就是在ES5发布之前,市面上各版互不兼容语言的子集。严格模式是可选的,也就是说,选择以严格模式执行的代码段(以函数为单位,或者整个程序)都必须要在其头部作如下声明:

"use strict";

这其实是一个 JavaScript 字符串。虽然我们并没有将其赋值给某个变量,执行后也不会有什么效果,但它符合JavaScript语法。因此不支持ES5严格模式的老式浏览器会直接忽略它,然后以普通的 JavaScript 对待其后的代码。也就是说,这种严格模式是向后兼容的,使用严格模式不会导致老式浏览器无法执行代码。

或许在将来的版本中,严格模式由可能会成为 ES 的默认模式,甚至是唯一模式。但现在它还只是一个可选项。

出于向后兼容的考虑,本书所有的示例都将遵守ES3规则,但同时本书中所有的代码也都能在ES5严格模式下正常执行,不会有任何警告。另外,本书中专门为ES5所写的部分会被清楚地标记出来。而关于ES5的新特性,我们在附录C,内建对象中会有详细收录。1.6面向对象的程序设计

在深入学习 JavaScript 之前,我们首先要了解一下“面向对象”的具体含义,以及这种程序设计风格的主要特征。下面我们列出了一系列在面向对象程序设计(OOP)中最常用到的概念:

对象、方法、属性;

类;

封装;

聚合;

重用与继承;

多态。

现在,我们就来详细了解每个概念。当然,如果您在面向对象程序设计方面是一个新手,或者不能确定自己是否真的理解了这些概念,那也不必太过担心。以后我们还会通过一些代码来为您具体分析它们。尽管这些概念说起来好像很复杂、很高级,但一旦我们进入真正的实践,事情往往就会简单得多。1.6.1 对象

既然这种程序设计风格叫做面向对象,那么其重点就应该在对象上。而所谓对象,实质上就是指“事物”(包括人和物)在程序设计语言中的表现形式。这里的“事物”可以是任何东西(如某个客观存在的对象,或者某些较为抽象的概念)。例如,对于猫这种常见对象来说,我们可以看到它们具有某些明确的特征(如颜色、名字、体型等),能执行某些动作(如喵喵叫、睡觉、躲起来、逃跑等)。在OOP语义中,这些对象特征都叫做属性,而那些动作则被称为方法。

此外,我们还有一个口语方面的类比。

对象往往是用名词来表示的(如book、person)。

方法一般都是些动词(如read、run)。

属性值则往往是一些形容词。

我们可以试一下。例如,在“The black cat sleeps on my head”这个句子中,“the cat”(名词)就是一个对象,“black”(形容词)则是一个颜色属性值,而“sleep”(动词)则代表一个动作,也就是OOP语义中的方法。甚至,为了进一步证明这种类比的合理性,我们也可以将句子中的“on my head”看做动作“sleep”的一个限定条件,因此,它也可以被当做传递给sleep方法的一个参数。1.6.2 类

在现实生活中,相似对象之间往往都有一些共同的组成特征。例如蜂鸟和老鹰都具有鸟类的特征,因此它们可以被统称为鸟类。在OOP中,类实际上就是对象的设计蓝图或制作配方。“对象”这个词,我们有时候也叫做“实例”,所以我们可以说老鹰是鸟类的一个实例。我们可以基于同一个类创建出许多不同的对象。因为类更多的是一种模板,而对象则是在这些模板的基础上被创建出来的实体。

但我们要明白,JavaScript与C++或Java这种传统的面向对象语言不同,它实际上压根儿没有类。该语言的一切都是基于对象的,其依靠的是一套原型(prototype)系统。而原型本身实际上也是一种对象,我们后面也会再来详细讨论这个问题。在传统的面向对象语言中,我们一般会这样描述自己的做法:“我基于Person类创建了一个叫做Bob的新对象。”而在这种基于原型的面向对象语言中,我们则要这样描述:“我将现有的Person对象扩展成了一个叫做Bob的新对象。”1.6.3 封装

封装是另一个与OOP相关的概念,其主要用于阐述对象中所包含的内容。封装概念通常由两部分组成。

相关的数据(用于存储属性)。

基于这些数据所能做的事(所能调用的方法)。

除此之外,这个术语中还有另一层信息隐藏的概念,这完全是另一方面的问题。因此,我们在理解这个概念时,必须要留意它在OOP中的具体语境。

以一个MP3播放器为例。如果我们假设它是一个对象,那么作为该对象的用户,我们无疑需要一些类似于像按钮、显示屏这样的工作接口。这些接口会帮助我们使用该对象(如播放歌曲之类)。至于它们内部是如何工作的,我们并不清楚,而且大多数情况下也不会在乎这些。换句话说,这些接口的实现对我们来说是隐藏的。同样的,在OOP中也是如此。当我们在代码中调用一个对象的方法时,无论该对象是来自我们自己的实现还是某个第三方库,我们都不需要知道该方法是如何工作的。在编译型语言中,我们甚至都无法查看这些对象的工作代码。由于 JavaScript 是一种解释型语言,源代码是可以查看的。但至少在封装概念上它们是一致的,即我们只需要知道所操作对象的接口,而不必去关心它的具体实现。

关于信息隐藏,还有另一方面内容,即方法与属性的可见性。在某些语言中,我们能通过 public、private、protected 这些关键字来限定方法和属性的可见性。这种限定分类定义了对象用户所能访问的层次。例如,private 方法只有其所在对象内部的代码才有权访问,而public方法则是任何人都能访问的。在JavaScript中,尽管所有的方法和属性都是public的,但是我们将会看到,该语言还是提供了一些隐藏数据的方法,以保护程序的隐密性。1.6.4 聚合

所谓聚合,有时候也叫做组合,实际上是指我们将几个现有对象合并成一个新对象的过程。总之,这个概念所强调的就是这种将多个对象合而为一的能力。通过聚合这种强有力的方法,我们可以将一个问题分解成多个更小的问题。这样一来,问题就会显得更易于管理(便于我们各个击破)。当一个问题域的复杂程度令我们难以接受时,我们就可以考虑将它分解成若干子问题区,并且必要的话,这些问题区还可以再继续分解成更小的分区。这样做有利于我们从几个不同的抽象层次来考虑这个问题。

例如,个人电脑是一个非常复杂的对象,我们不可能知道它启动时所发生的全部事情。但如果我们将这个问题的抽象级别降低到一定的程度,只关注它几个组件对象的初始化工作,例如显示器对象、鼠标对象、键盘对象等,我们就很容易深入了解这些子对象情况,然后再将这些部分的结果合并起来,之前那个复杂问题就迎刃而解了。

我们还可以找到其他类似情况,例如Book是由一个或多个author对象、publisher对象、若干chapter对象以及一组table对象等组合(聚合)而成的对象。1.6.5 继承

通过继承这种方式,我们可以非常优雅地实现对现有代码的重用。例如,我们有一个叫做Person的一般性对象,其中包含一些姓名、出生日期之类的属性,以及一些功能性函数,如步行、谈话、睡觉、吃饭等。然后,当我们发现自己需要一个Programmer对象时,当然,这时候你可以再将Person对象中所有的方法与属性重新实现一遍,但除此之外还有一种更聪明的做法,即我们可以让Programmer继承自Person,这样就省去了我们不少工作。因为Programmer对象只需要实现属于它自己的那部分特殊功能(例如“编写代码”),而其余部分只需重用Person的实现即可。

在传统的OOP环境中,继承通常指的是类与类之间的关系,但由于JavaScript中不存在类,因此它的继承只能发生在对象之间。

当一个对象继承自另一个对象时,通常会往其中加入新的方法,以扩展被继承的老对象。我们通常将这一过程称之为“B继承自A”或者“B扩展自A”。另外对于新对象来说,它也可以根据自己的需要,从继承的那组方法中选择几个来重新定义。这样做并不会改变对象的接口,因为其方法名是相同的,只不过当我们调用新对象时,该方法的行为与之前不同了。我们将这种重定义继承方法的过程叫做覆写。1.6.6 多态

在之前的例子中,我们的Programmer对象继承了上一级对象Person的所有方法。这意味着这两个对象都实现了“talk”等方法。现在,我们的代码中有一个叫做Bob的变量,即便是在我们不知道它是一个 Person 对象还是一个 Programmer 对象情况下,也依然可以直接调用该对象的“talk”方法,而不必担心这会影响代码的正常工作。类似这种不同对象通过相同的方法调用来实现各自行为的能力,我们就称之为多态。1.7OOP小结

下面,让我们再来回顾一下这些概念(见表1-1)。表1-1续表1.8训练环境设置

在这本书中,凡涉及代码的我们都强调“自己动手”,因为在我们的理念中,学好一门编程语言最好的途径就是不停地编写代码。因此,这里将不提供任何可供您直接复制/粘贴的代码下载。恰恰相反,我们必须得让您亲自来输入代码,并观察它们是如何工作的,思考需要做哪些调整,这样周而复始地摆弄它们。因而,当您想尝试这些代码示例时,我们建议您使用JavaScript控制台这一类的工具。下面就让我们来看看这些工具是如何使用的。

对于开发人员来说,机器上应该大多都早已安装了一些Web浏览器了,例如Firefox、Safari、Chrome 或Internet Explorer。而所有现代浏览器中都应该自带了JavaScript 控制台组件,该组件是我们在阅读本书过程中始终会用到的东西,是帮助您进行语言学习和实验的环境。更具体地说,尽管本书用的是WebKit控制台(Safari和Chrome都支持该控制台),但书中的这些示例在任何控制台上都是能正常工作的。1.8.1 WebKit所附带的Web审查工具

图1-1展示了如何在控制台中通过输入代码的方式将google.com主页上的logo换成我们自己指定的图片。如您所见,我们可以在任何页面上测试这段JavaScript代码。

在Chrome和Safari中,您可以通过右键单击相关页面,并选择“审查元素”来打开控制台。然后Web审查工具就会出现在下面的弹出窗口中,我们选择其标签栏上的“控制台”标签,就来到了真正的控制台界面中。

然后,我们直接在控制台中输入代码,按下回车键,代码就会被执行。其返回值也会在控制台中被打印出来。代码会在当前页面的上下文环境中运行,所以,如果您在其中输入location.href,控制台就会返回当前页面的 URL。除此之外,该控制台还具有一套自动完成功能,其工作方式与我们平时所用的操作系统命令行类似。举个例子,如果我们在其中输入docu,然后按Tab键,docu就会被自动补全为document。这时如果再继续输入一个“.”(点操作符),我们就可以通过重复按Tab键的方式来遍历document对象中所有可调用的方法和属性。图1-1

另外通过上下箭头键,我们还可以随时从相关列表中找回已经执行过的命令,并在控制台中重新执行它们。

通常情况下,控制台只提供单行输入,但我们可以用分号做分割符来执行多个JavaScript语句。而如果您需要更多行代码的话,也可以通过组合键shift+Enter来实现换行,在这种情况下代码不会被立即执行。1.8.2 Mac上的JavaScriptCore

在Mac上,我们事实上不用浏览器也可以通过终端来执行JavaScript。

如果您之前没有使用过终端,可以通过Spotlight找到它。打开终端之后,在其中输入:

alias jsc='/System/Library/Frameworks/JavaScriptCore.framework/Versions/Current/Resources/jsc'

该命令为JSC(即JavaScriptCore)设置了一个别名。JSC其实是WebKit引擎的一部分。Mac系统自带有该引擎。

我们也可以直接将这个alias命令放入~/.profile文件,这样每次打开终端时,都可以通过jsc这个别名来启动JavaScriptCore了。

现在,终端在任何目录下都可以通过直接输入 jsc 来打开其交互环境了。然后您可以在其中输入相关的 JavaScript 表达式。按下 Enter 键之后,表达式的结果就会被显示出来,如图1-2所示。图1-21.8.3 更多控制台

如今,几乎所有现代浏览器都有自带的控制台。除了之前提到的Chrome及Safari的控制台之外,FireFox浏览器的所有版本也都能安装Firebug组件,该组件中也有一个控制台。另外,新版的Firefox中也有一个自带的控制台,您可以通过菜单栏“工具/Web开发者/Web控制台”来打开它,如图1-3所示。图1-3

而Internet Explorer从第8版开始,只要按下F12键就可以打开开发者工具组件。打开后,按Script标签栏就可进入控制台。

另外,通过 Node.js 的交互环境来学习 JavaScript 也是一个不错的选择。您可以从http://nodejs.org中获取并安装Node.js,然后在终端中尝试其控制台,如图1-4所示。图1-4

如您所见,我们既可以用Node.js的控制台测试一些小型示例,同时也可以写一些较长的shell脚本(如截图中的test.js),然后以scriptname.js的形式在Node.js的终端中执行。1.9本章小结

在这一章中,我们首先介绍了 JavaScript 语言的发展历程和现状。然后,对面向对象程序设计的概念进行了一些基本论述。接着,我们向您详细阐述了为什么 JavaScript 不是传统的基于类的面向对象语言,而是一套独特的原型系统。现在,您已经为下一步深入学习JavaScript语言、掌握其面向对象特性打下了一定的基础,但让我们一步步来。

下一章将会介绍JavaScript的数据类型(JavaScript的数据类型非常少),以及条件、循环语句和数组。如果您确信自己已经掌握了这些知识,并且对该章结尾处的那几个小练习完全没有疑问的话,那么就请自行跳过这一章吧。第2章基本数据类型、数组、循环及条件表达式

在深入学习JavaScript的面向对象特性之前,我们首先要了解一些基础性知识。在这一章中,我们将会从以下几个方面入手。

JavaScript 中的基本数据类型,例如字符串和数字等。

数组。

常用操作符,例如+、-、delete、typeof 等。

控制流语句,例如循环和if-else 条件表达式等。2.1变量

通常,变量都是用来存储数据的,即它是存放具体数值的容器。当我们编写程序时,用变量来表示实际数据会更方便些。尤其是当我们需要多次使用某个数字时,使用变量pi显然要比直接写数字值3.141592653589793方便得多。而且,之所以称它们为“变”量,就是因为它们所存储的数据在初始化之后仍然是可以改变的。另外,在编写代码时我们往往也可以用变量来代表某些程序运行前还未知的数据,例如某个计算的结果值。

变量的使用通常可分为以下两个步骤。

声明变量。

初始化变量,即给它一个初始值。

我们可以使用var语句来声明变量,像这样:

var a;

var thisIsAVariable;

var _and_this_too;

var mix12three;

变量名可以由字母、数字、下划线及美元符号组合而成。但不能以数字开头,像下面这样是不被允许的:

var 2three4five;

而所谓的变量初始化,实际上指的是变量的第一次赋值。我们可以有以下两种选择。

先声明变量,然后再初始化。

声明变量与初始化同步进行。

下面是后一种写法的例子:

var a = 1;

这样,我们就声明了一个名为a、值为1的变量。

另外,我们也可以在单个 var 语句中同时声明(并初始化)多个变量,只要将它们分别用逗号分开即可,例如:

var v1, v2, v3 = 'hello', v4 = 42, v5;

有时候出于代码可读性方面的考虑,我们可能还会这么写:

var v1,

v2,

v3 = 'hello',

v4 = 42,

v5;

变量名中的$符号

变量名中可以使用$符号,例如$myvar,或者品味还可以更独特一点,my$var。按照变量命名规范,美元符号允许出现在任意位置,但其实旧版的ECMA标准是不鼓励使用美元符号命名变量的,它只建议在生成代码(即由其他程序输出的代码)中使用。但显然JavaScript社区并没有接受该建议,在实际项目中,以单独一个$符为函数名的做法比比皆是。

区分大小写

在JavaScript语言中,变量名是区分大小写的。为了证明这一点,我们可以在JavaScript控制台中测试下列语句(每输入一行按一次Enter键):

var case_matters = 'lower';

var CASE_MATTERS = 'upper';

case_matters;

CASE_MATTERS;

为了减少按键的次数,在输入第三行时,我们可以先键入ca然后按Tab键(或右方向键),控制台会自动将其补全为case_matters。最后一行也是如此,我们只需先输入CASE然后直接按Tab即可。输入完成之后,最终结果如图2-1所示。

为方便起见,以后我们将用代码形式来代替截图。上面的例子可以表示如下:

> var case_matters = 'lower';

> var CASE_MATTERS = 'upper';

> case_matters;

"lower"

> CASE_MATTERS;

"upper"

如您所见,大于号(>)之后的内容就是我们输入的代码,而其余部分则是控制台输出的结果。需要强调的是,当您测试类似的代码时,应该根据实验的实际情况来调整相关代码。这才能有助于您更好地理解语言的工作方式。图2-1

读者有时可能会看到某个表达式在控制台中的输出结果为undefined。这大多数情况下是完全可以忽略的,但您有没有想过,为什么这些表达式会输出 undefined呢?那是因为控制台在执行完我们输入的表达式之后,总是要输出该表达式的运行结果。但有一些表达式(例如var a = 1;)是没有任何返回值的。在这种情况下,控制台就会隐式打印一个 undefined。相反地,当一个表达式确实有返回值时,比如之前的例子中的case_matters或是1+1之类的表达式,控制台就会将该表达式的实际返回值打印出来。当然,并不是所有的控制台都会在没有返回值时打印 undefined 值,例如Firebug控制台就不会这样做。2.2操作符

所谓操作符,通常指的是能对一两个输入执行某种操作,并返回结果的符号。为了更清晰地表达该术语的含义,我们先来看一个具体的示例:

> 1 + 2;

3

这段代码包含了以下几点信息。

+是一个操作符。

该操作是一次加法运算。

输入值为1 和2(输入值也叫做操作数)。

结果值为3。

1 + 2 这个整体称为表达式。

在这里,1 和 2 都是直接参与加法运算的。接下来我们要将它们换成变量,并再另外声明一个变量来存储运算结果。具体如下:

> var a = 1;

> var b = 2;

> a + 1;

2

> b + 2;

4

> a + b;

3

> var c = a + b;

> c;

3

在表2-1中,我们列出了一些基本的算术运算符。表2-1续表续表

事实上,当我们输入var a = 1;这样的语句时,所执行的也是一种独立的操作。这种操作叫做纯赋值,因而“=”也被称为简单赋值运算符(simple assignment operator)。

除此之外,JavaScript中还有一组由算术运算和赋值操作组合而成的操作符。我们称它们为复合操作符(compound operator)。这些操作符能让我们的代码显得更为紧凑。下面来看几个示例:

> var a = 5;

> a += 3;

8

在该例中,a += 3;实际上就相当于a = a + 3;的缩写形式。

> a -= 3;

5

同理,这里的a -= 3;等同于a = a - 3;。

以此类推:

> a *= 2;

10

> a /= 5;

2

> a %= 2;

0

除了我们已经提到的算术运算与赋值操作以外,JavaScript 中还有其他各种类型的操作符。我们将会在后面的章节中陆续看到。

最佳实践

表达式应始终是以分号为结束符的。尽管JavaScript本身设有分号补全机制,即如果您忘了在一行表达式之后添加分号,该位置就会被隐式地补上一个分号。但这种机制同时也是出错的主要源头之一。所以,最好还是我们自己要记得在表达式结束之后明确地用分号来关闭该表达式。换句话说,虽然 > 1 + 1与 > 1 + 1;都属于合法的表达式,但为了强调这一良好的编程习惯,本书将一律采用后一种形式。2.3基本数据类型

我们在程序中所使用的任何值都是有类型的。JavaScript 仅有以下几大基本数据类型。

1.数字——包括浮点数与整数,例如这些都属于数字:1、100、3.14。

2.字符串——包括由任意数量字符组成的序列,例如:"a"、"one"、"one 2 three"。

3.布尔值——包括true和false。

4.undefined——当我们试图访问一个不存在的变量时,就会得到一个特殊值:undefined。除此之外,使用已声明却未赋值的变量也会如此。因为JavaScript会自动将变量在初始化之前的值设定为 undefined。而 undefined 类型的值只有一个—undefined。

5.null——这是另一种只包含一个值的特殊数据类型。所谓的 null 值,通常是指没有值或空值,不代表任何东西。null与undefined最大的不同在于,被赋予null的变量通常被认为是已经定义了的,只不过它不代表任何东西。关于这一点,我们稍后会通过一些具体的示例来解释。

任何不属于上述五种基本类型的值都会被认为是一个对象。甚至有时候我们也会将null视为对象,这听起来有些尴尬——这是一个不代表任何东西的对象(东西)。我们将会在第4章:对象中深入阐述对象的概念,现在我们只需要记住一点,JavaScript中的数据类型主要分为以下两个部分:

基本类型(上面列出的五种类型)。

非基本类型(即对象)。2.3.1 查看类型操作符——typeof

如果我们想知道某个变量或值的类型是什么,可以调用特殊操作符 typeof。该操作符会返回一个代表数据类型的字符串,以下是其可能返回的结果:

"number";

"string";

"boolean";

试读结束[说明:试读内容隐藏了图片]

下载完整电子书


相关推荐

最新文章


© 2020 txtepub下载