JavaScript:概念

在正式的讨论之前,应当先理清楚JavaScript中的一些重要概念,这些概念在后续章节中会经常碰到,我们先来快速过一下。

面向对象

JavaScript是一门面向对象的编程语言,这一点对于那些对JavaScript了解不多的开发者来说的确有点意外。你所能接触到的任何JavaScript代码片段都可以作为对象。只有五类原始类型不是对象,它们是数字、字符串、布尔值、nullundefined,数字、字符串和布尔值类型都有与之对应的包装对象(下一章会讲到),可以轻易的转换为对象类型,可以通过手动转换,也可以利用JavaScript解析器进行自动转换。

函数也是对象,也可以拥有属性和方法。

在任何语言中,最简单的操作莫过于定义变量。在JavaScript中定义变量的时候,其实也在和对象打交道。首先,变量自动成为一个内置对象的属性(这个内置对象被称作“活动对象”,如果是全局变量的话,就变为全局对象的属性)。其次,这个变量实际上也是“伪对象”,因为它有自己的属性(译注:原文使用了attributes,指内置的特性),用以表示变量是否可以被修改、删除或在for-in中枚举。这些特性并未在ECMAScript3中作规定,但ECMAScript5中提供了一组可以修改这些特性的方法。

那么,到底什么是对象?对象能做这么多事情,那它们一定非常特别。实际上,对象是极其简单的。对象只是很多属性的集合,一个名值对的列表(在其他语言中可能被称作关联数组),这些属性也可以是函数(函数对象),这种函数我们称为“方法”。

关于对象,我们还需要了解,我们可以随时随地修改已经创建的对象(ECMAScript5中提供了可阻止这些修改的API)。得到一个对象后,你可以给他添加、删除或更新成员。如果你关心私有成员和访问控制,我们也会在本书中讲到相关的模式。

最后一个需要注意的是,对象有两大类:

  • 本地对象(Native):由ECMAScript标准定义的对象
  • 宿主对象(Host):由宿主环境创建的对象(比如浏览器环境)

本地对象也可以被归类为内置对象(比如ArrayDate)或自定义对象(var o = {})。(译注:指本地对象包含内置对象和自定义对象。)

宿主对象包含window和所有DOM对象。如果你想知道你是否在使用宿主对象,将你的代码迁移到一个非浏览器环境中运行一下,如果正常工作,那么你的代码就只用到了本地对象。

没有类

在本书中的许多场合都会反复碰到这个概念。JavaScript中没有类,对于其他语言的编程老手来说这个观念非常新颖,需要反复的琢磨和重新学习才能理解JavaScript只能处理对象的观念。

没有类,你的代码会变得更小巧,因为你不必使用类去创建对象,看一下Java风格的对象创建:

  1. // Java中创建对象
  2. HelloOO hello_oo = new HelloOO();

为了创建一个简单的对象,同样一件事情重复做了三遍,这让这段代码看起来很“重”。而大多数情况下,我们想让我们的对象保持简单。

在JavaScript中,你需要一个对象,就随手创建一个空对象,然后给这个对象添加你需要的成员。你可以给它添加原始值、函数或其他对象作为这个对象属性。“空”对象并不是真正的空,对象中存在一些内置的属性,但并没有“自有属性”。在下一章里我们对此作详细讨论。

“GoF”的书中提到一条通用规则,“组合优于继承”,也就是说,如果你手头有创建这个对象所需的资源,更推荐直接将这些资源组装成你所需的对象,而不推荐通过先做分类再创建链式父子继承的方式来创建对象。在JavaScript中,这条规则非常容易遵守,因为JavaScript中没有类,而对象组装无处不在。

原型

尽管继承只是实现代码复用的其中一种方式,但在JavaScript中的确有继承(本书有专门的一章来讨论代码复用)。继承可以通过多种方式实现,最常用的就是利用原型。“原型”(prototype)是一个普通的对象,你所创建的每一个函数会自动带有prototype属性,这个属性指向一个空对象,这个空对象包含一个constructor属性,它指向你新建的函数而不是内置的Object()。除此之外,它和通过对象直接量或Object()构造函数创建的对象没什么两样。你可以给它添加新的成员,这些成员可以被其他对象继承,并当作其他对象的自有属性来使用。

我们后面会详细讨论JavaScript中的继承,现在只要记住:原型是一个对象(不是类或者其他什么特别的东西),每个函数都有一个prototype属性。

运行环境

JavaScript程序需要一个运行环境。最理所当然的运行环境就是浏览器,但这绝不是唯一的运行环境。本书所讨论的编程模式更多的和JavaScript语言核心(ECMAScript)相关,因此这些编程模式是环境无关的。除了有两个例外:

  • 第八章,这一章专门讲述浏览器相关的模式
  • 一些演示模式用法的实际程序

运行环境会提供自己的宿主对象,这些宿主对象并未在ECMAScript标准中定义,因此它们的行为也是不可预知的。