1、原型(prototype)是什么?与构造函数和对象有什么关系?
Js中对象的prototype属性,是该对象的构造函数的原型的引用。
图示说明:
——理解原型、构造函数(类)、对象的关系
《Javascript王者归来》一书中打了个很贴切的比方,习语有“照猫画虎”,可以理解为“照着‘某只猫’画出一类虎”,那么由这类虎构造的具体的‘某只虎’也就继承了这只猫的所有属性。这里的“某只猫”就是原型,而“虎”就是类型(构造函数)。那么具体的“某只虎”就是构造函数“虎”的一个对象实例。
用Js代码表示就是:“虎.prototype=某只猫”或“虎.prototype=new 猫()”、“某只虎=new 虎()”、“某只虎.prototype=某只猫”。
概念化:
- 所有的构造函数都有一个prototype属性。当函数被定义的时候,prototype属性自动创建和初始化,初始化值是一个对象。这个原型对象只带有一个属性constructor,它指回到和原型相关联的那个构造函数(这也就是每个对象都有一个constructor属性的原因)。
- 添加给这个原型的任何一个属性,都会成为对应构造函数创建的对象的属性。即对象从它的原型那里继承属性。
2、prototype的特性
- 原型模式(prototype pattern)要求 一个类型(这里指构造函数)一个时刻只能有一个原型。
- 这个类型(构造函数)的所有实例(对象),必须满足原型关系的类型链。
—— 一个例子:
<script type="text/javascript" language="javascript"> function ClassA() { } //默认时ClassA.prototype=new Object(); var ObjectA = new ClassA(); function ClassB() { this.b = "hello"; } ClassB.prototype = ObjectA; //ClassB以ClassA的对象为原型 var ObjectB = new ClassB(); function ClassC() { this.c = "c"; } ClassC.prototype = ObjectB; //ClassC以ClassB的对象为原型 var ObjectC = new ClassC(); alert(ObjectC instanceof ClassC);//true alert(ObjectC instanceof ClassB);//true alert(ObjectC instanceof ClassA);//true alert(ObjectC instanceof Object);//true </script>
上面例子中的关系可用下图表示(略去内部的constructor和prototype属性的表示):
3、prototype的使用
(1)给类的原型对象添加或删除属性。
—— 这一操作将直接影响相应的类(构造函数)创建的所有对象。
例:
<script language="javascript" type="text/javascript"> function print(msg) { document.write(msg + "<br/>"); } function Point(x, y) { this.x = x; this.y = y; } var p1 = new Point(1, 2); var p2 = new Point(3, 4); Point.prototype.z = 0; //给Point函数的原型添加z属性,赋初值0 print(p1.z);//输出0 print(p2.z);//输出0 </script>
(2)使用prototype创建大量副本
—— 一般情况下,用prototype创建复杂对象的大量副本比其他方式来copy对象要快得多。
- 以一个对象为原型,创建大量新的对象,正是原型模式(prototype pattern)的本质。
<script language="javascript" type="text/javascript"> ……
var p1 = new Point(1, 2); var points = []; //定义一个数组 function PointPrototype() { } //定义一个空函数PointPrototype PointPrototype.prototype = p1; //将PointPrototype的原型设置为对象p1 for (var i = 0; i < 10000; i++) { points[i] = new PointPrototype(); //因为PointPrototype的构造函数是空函数,所有它比直接构造p1的副本快得多。 } </script>
(3)用prototype定义静态方法
—— 习惯上,将采用prototype定义的属性和方法称为“静态属性”和“静态方法”(或称为“原型属性”和“原型方法”)。将this定义的属性和方法称为“公有属性”和“公有方法”。
<script language="javascript" type="text/javascript"> function Point(x, y) { this.x = x; this.y = y; } Point.prototype.distance = function() { return Math.sqrt(this.x * this.x + this.y * this.y); }//用prototype避免每次调用构造函数时对this.distance的赋值操作。 </script>
注意:尽量采用prototype定义对象方法,除非该方法需要创建闭包。