您的位置:首页 > Web前端 > JavaScript

面向对象的JS神奇的 prototype

2011-02-23 22:05 330 查看
对于初学 JavaScript 的人来说 prototype 是一种很神奇的特性,而事实上,prototype 对于 JavaScript 的意义重大,prototype 不仅仅是一种管理对象继承的机制,更是一种出色的设计思想。 21.2.1 什么是 prototype JavaScript 中对象的 prototype 属性,可以返回对象类型原型的引用。这是一个相当拗口的解释,要理解它,先要正确理解对象类型(Type)以及原型(prototype)的概念。 前面我们说,对象的类(Class)和对象实例(Instance)之间是一种“创建”关系,因此我们把“类”看作是对象特征的模型化,而对象看作是类特征的具体化,或者说,类(Class)是对象的一个类型(Type)。例如,在前面的例子中,p1 和p2 的类型都是 Point,在 JavaScript 中,通过instanceof运算符可以验证这一点: p1 instanceof Point p2 instanceof Point 但是,Point 不是 p1 和 p2 的唯一类型,因为 p1 和 p2 都是对象,所以 Obejct 也是它们的类型,因为Object 是比 Point 更加泛化的类,所以我们说,Obejct和 Point之间有一种衍生关系,在后面我们会知道,这种关系被叫做“继承”,它也是对象之间泛化关系的一个特例,是面向对象中不可缺少的一种基本关系。 在面向对象领域里,实例与类型不是唯一的一对可描述的抽象关系,在 JavaScript 中,另外一种重要的抽象关系是类型(Type)与原型(prototype)。这种关系是一种更高层次的抽象关系,它恰好和类型与实例的抽象关系构成了一个三层的链,图 21.2 描述了这种关系:

                        图 21.2 对象、类型与原型的关系

在现实生活中,我们常常说,某个东西是以另一个东西为原型创作的。这两个东西可以是同一个类型,也可以是不同类型。习语“照猫画虎”,这里的猫就是原型,而虎就是类型,用 JavaScript的 prototype 来表示就是“虎.prototype =某只猫”或者“虎.prototype= new 猫()”。 “原型”是描述自然界事物之间“归类”关系的一种,另外几种关系包括“继承”和“接口”。一般来说,“继承”描述的是事物之间固有的衍生关系,能被“继承”所描述的事物之间具有很强的关联性(血缘)。“接口”描述的是事物功用方面的共同特征。而“原型”则倾向于描述事物之间的“相似性”。从这一点来看,“原型”在描述事物关联性的方面,比继承和接口更加广义。 如果你是 Java 程序员,上面的例子从继承的角度来考虑,当然不可能用“猫”去继承“虎”,也不可能用“虎”去继承“猫”,要描述它们的关系,需要建立一个涵盖了它们共性的“抽象类”,或者你会叫它“猫科动物”。可是,如果我的系统中只需要用到“猫”和“老虎”,那么这个多余的“猫科动物”对于我来说没有任何意义,我只需要表达的是,“老虎”有点像“猫”,仅此而已。在这里,用原型帮我们成功地节省了一个没有必要建立的类型“猫科动物”。 要深入理解原型,可以研究关于它的一种设计模式——prototype pattern,这种模式的核心是用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。JavaScript 的 prototype 就类似于这种方式。 关于 prototype pattern的详细内容可以参考《设计模式》(《Design Patterns》)它不是本书讨论的范围。 注意,原型模式要求一个类型在一个时刻只能有一个原型(而一个实例在一个时刻显然可以有多个类型)。对于 JavaScript 来说,这个限制有两层含义,第一是每个具体的 JavaScript 类型有且仅有一个原型(prototype),在默认的情况下,该原型是一个 Object 对象(注意不是 Object 类型!)。第二是,这个类型的实例的所有类型,必须是满足原型关系的类型链。例如 p1 所属的类型是 Point 和 Object,而一个 Object对象是 Point 的原型。假如有一个对象,它所属的类型分别为 ClassA、ClassB、ClassC 和 Object,那么必须满足这四个类构成某种完整的原型链,例如:

例 21.4 原型关系的类型链

function ClassA()

{

……

}

ClassA.prototype = new Object(); //这个可以省略

function ClassB()

{

……

}

ClassB.prototype = new ClassA(); //ClassB以 ClassA的对象为原型

function ClassC()

{

   ……

}

ClassC.prototype = new ClassB(); //ClassC以 ClassB的对象为原型

var obj = new ClassC();

alert(obj instanceof ClassC); //true

alert(obj instanceof ClassB); //true

alert(obj instanceof ClassA); //true

alert(obj instanceof Object); //true

图 21.3 简单描述了它们之间的关系:

图 21.3 原型关系的类型链

有意思的是,JavaScript并没有规定一个类型的原型的类型(这又是一段非常拗口的话),因此它可以是任何类型,通常是某种对象,这样,对象-类型-原形(对象)就可能构成一个环状结构,或者其它有意思的拓扑结构,这些结构为 JavaScript 带来了五花八门的用法,其中的一些用法不但巧妙而且充满美感。下面的一节主要介绍 prototype 的用法。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: