这一次我们深入的学习一下JavaScript面向对象技术,在学习之前,必要的说明一下一些面向对象的一些术语。这也是所有面对对象语言所拥有的共同点。有这样几个面向对象术语:
一、对象
ECMA-262把对象(object)定义为“属性的无序集合,每个属性存放一个原始值、对象或函数”。严格来说,这意味着对象是无特定顺序的值的数组。尽管ECMAScript如此定义对象,但它更通用的定义是基于代码的名词(人、地点或事物)的表示。
二、类
每个对象都由类定义,可以把类看做对象的配方。类不仅要定义对象的接口(interface)(开发者访问的属性和方法),还要定义对象的内部工作(使属性和方法发挥作用的代码)。编译器和解释程序都根据类的说明构建对象。
三、实例
程序使用类创建对象时,生成的对象叫作类的实例(instance)。对类生成的对象的个数的唯一限制来自于运行代码的机器的物理内存。每个实例的行为相同,但实例处理一组独立的数据。由类创建对象实例的过程叫做实例化(instantiation)。
在前面的章节我们提到过,ECMAScript并没有正式的类。相反,ECMA-262把对象定义描述为对象的配方。这是 ECMAScript逻辑上的一种折中方案,因为对象定义实际上是对象自身。即使类并不真正存在,我们也把对象定义叫做类,因为大多数开发者对此术语更熟悉,而且从功能上说,两者是等价的。
使用预定义对象只是面向对象语言的能力的一部分,它真正强大之处在于能够创建自己专用的对象。ECMAScript 拥有很多创建对象的方法。
1、原始方式
因为对象的属性可以在对象创建后动态定义,所有许多开发者都在JavaScript 最初引入时编写类似下面的代码:
var Car = new Object(); Car.color = "blue"; Car.doors = 4; Car.mpg = 25; Car.showColor = function() { return this.color; }; document.write(Car.showColor());//输出:blue
在上面的代码中,创建对象Car。然后给它设置几个属性:它的颜色是蓝色,有四个门,每加仑油可以跑 25 英里。最后一个属性实际上是指向函数的指针,意味着该属性是个方法。执行这段代码后,就可以使用对象Car。不过这里有一个问题,就是可能需要创建多个Car的实例,这样就造成了我们会重复许多类似的代码,这样会很麻烦。
2、工厂方式
要解上述的多个类似对象声明的问题,开发者创造了能创建并返回特定类型的对象的工厂方式。这种方式就是为了解决实例化对象产生大量重复的问题。
(1)无参数的工厂方式
例如,函数createCar()可用于封装前面列出的创建Car对象的操作:
function createCar() { var TempCar = new Object(); TempCar.color = "blue"; TempCar.doors = 4; TempCar.mpg = 25; TempCar.showColor = function() { return this.color; }; return TempCar; }; var Car1 = createCar(); var Car2 = createCar(); document.write(Car1.showColor()+"<br/>");//输出:blue document.write(Car2.showColor());//输出:blue
在这里,第一个例子中的所有代码都包含在createCar()函数中。此外,还有一行额外的代码,返回TempCar 对象作为函数值。调用此函数,将创建新对象,并赋予它所有必要的属性,复制出一个我们在前面说明过的Car对象。因此,通过这种方法,我们可以很容易地创建Car对象的两个版本(Car1和 Car2),它们的属性完全一样。
(2)有参数的工厂方式
我们还可以修改createCar()函数,给它传递各个属性的默认值,而不是简单地赋予属性默认值:
function createCar(Color,Doors,Mpg) { var TempCar = new Object(); TempCar.color = Color; TempCar.doors = Doors; TempCar.mpg = Mpg; TempCar.showColor = function() { return this.color; }; return TempCar; }; var Car1 = createCar("red",4,23); var Car2 = createCar("blue",3,25); document.write(Car1.showColor()+"<br/>");//输出:red document.write(Car2.showColor());//输出:blue
给createCar()函数加上参数,即可为要创建的Car对象的color、doors 和mpg属性赋值。这使两个对象具有相同的属性,却有不同的属性值。
工厂方式解决了重复实例化的问题,但是还是有一个问题,那就是前面的例子中,每次调用函数createCar(),都要创建新函数showColor(),意味着每个对象都有自己的 showColor() 版本。而事实上,每个对象都共享同一个函数。有些开发者在工厂函数外定义对象的方法,然后通过属性指向该方法,从而避免这个问题: