1.原型链
每个构造函数都有一个原型对象,原型对象含有一个指向构造函数的指针,而实例包含一个指向原型对象的内部指针。将原型对象等于另一个类型的实例,那么此时的原型对象将包含一个指向另一个原型的指针,相应地另外一个原型中包含着一个指向另外一个构造函数的指针。假如另一个原型又是另外一个构造函数的实例,将依序前面所述关系,层层递进,就构成了实例与原型的链条。
实现原型代码模式:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18function SuperType(){
this.property = true;
}
SuperType.prototype.getSuperValue = function(){
return this.property;
}
function SubType(){
this.subProperty = false;
}
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function(){
return this.subProperty;
}
var instance = new subType();
alert(instance.getSuperValue()); // true;
a.默认原型
所有函数的默认原型都是Object的实例,因此默认函数内部都包含一个指针,指向Object.prototype。这也正是所有自定义类型都会继承toString(),valueOf()等方法的原因。
b.确定实例与原型之间的关系
两个方法:instanceof和isPrototypeof()
c.谨慎定义方法
i.子类型需要重写超类型中的方法,或者添加超类型中不存在的方法时,一定要把给原型添加的方法代码放到替换原型的代码之后。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21function SuperType(){
this.property = true;
}
SuperType.prototype.getSuperValue = function(){
return this.property;
};
function SubType(){
this.subproperty = false;
}
//继承了 SuperType
SubType.prototype = new SuperType();
//添加新方法
SubType.prototype.getSubValue = function (){
return this.subproperty;
};
//重写超类型中的方法
SubType.prototype.getSuperValue = function (){
return false;
};
var instance = new SubType();
alert(instance.getSuperValue()); //false
ii.在给子类型替换原型代码之后,不能以字面量对象的方式给子类型原型添加方法。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22function SuperType(){
this.property = true;
}
SuperType.prototype.getSuperValue = function(){
return this.property;
};
function SubType(){
this.subproperty = false;
}
//继承了 SuperType
SubType.prototype = new SuperType();
//使用字面量添加新方法,会导致上一行代码无效
SubType.prototype = {
getSubValue : function (){
return this.subproperty;
},
someOtherMethod : function (){
return false;
}
};
var instance = new SubType();
alert(instance.getSuperValue()); //error!
d.原型链问题
第一个问题是包含引用类型值的原型,包含引用类型的值的原型属性会被所有实例所共享。
第二个问题是在创建子类型实例的时候,不能向超类型的构造函数中传递参数。1
2
3
4
5
6
7
8
9
10
11function SuperType(){
this.colors = ["red", "blue", "green"];
}
function SubType(){}
SubType.prototype = new SuperType();
var instance1 = new SubType();
instance1.colors.push("black");
var instance2 = new SubType();
alert(instance2.colors); // "red, blue, green, black"
2.借用构造函数
基本思想:在子类型构造函数内部通过call或者apply()方法调用超类型构造函数。函数在特定环境下是对象。
1 | function SuperType(){ |
a.传递参数
1 | function SuperType(name){ |
在SubType构造函数中调用SuperType构造函数时,实际上是为SubType构造函数添加了name属性。
b.借用构造函数的问题
单独使用构造函数模式,会让方法无法复用。并且在超类型的原型中的方法,无法让子类型实例继承。
3.组合使用原型链和借用构造函数
思路:使用原型链实现对原型的属性和方法的继承,而通过借用构造来实现对实例属性的继承,从而发挥二者之长。
1 | function SuperType(name){ |
3. 原型式继承
道格拉斯·克罗克福德2006年提出的这个方法。这种方法并没有严格意义上创建构造函数。他的想法是借助原型可以基于已有的对象创建对象,同时还不必因此创建自定义类型。他给出的函数:1
2
3
4
5function object(o){
function F(){};
F.prototype = o;
return new F();
}
在 object()函数内部,先创建了一个临时性的构造函数,然后将传入的对象作为这个构造函数的原型,最后返回了这个临时类型的一个新实例。1
2
3
4
5
6
7
8
9
10
11
12
13var person = {
name: "Nicholas",
friends: ["Shelby", "Court", "Van"]
};
var anotherPerson = object(person);
anotherPerson.name = "Greg";
anotherPerson.friends.push("Rob");
var yetAnotherPerson = object(person);
yetAnotherPerson.name = "Linda";
yetAnotherPerson.friends.push("Barbie");
alert(person.friends); //"Shelby,Court,Van,Rob,Barbie"
ECMAScript 5 通过新增 Object.create()方法规范化了原型式继承。这个方法接收两个参数:一个用作新对象原型的对象和(可选的)一个为新对象定义额外属性的对象。
第二个参数与Object.defineProperties()方法的第二个参数格式相同:每个属性都是通过自己的描述符定义的。
支持 Object.create()方法的浏览器有 IE9+、 Firefox 4+、 Safari 5+、 Opera 12+和 Chrome。
1 | var person = { |