0%

组合继承和原型继承

组合继承

综合了原型链和盗用构造函数,将两者优点结合,使用原型链继承原型上的属性和方法,通过盗用构造函数继承实例属性,这样既可以把方法定义在原型上实现重用,又可以让每个实例都有自己的属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
function SuperType(name){
this.name=name;
this.colors=["red","blue","green"];
}
SuperType.prototype.sayName=function(){
console.log(this.name);//不能用箭头函数,因为箭头函数没有this绑定,会向上找到全局上下文
}
function SubType(name,age) {
SuperType.call(this,name);//SuperType的构造函数绑定SubType的构造函数,自定义实例属性,第二次调用SuperType
this.age=age;
}
//继承原型上的方法,让SubType的原型指向SuperType的实例,第一次调用SuperType,SubType的constructor会委托到SuperType.prototype上的constructor,进而指向SuperType
SubType.prototype=new SuperType();
SubType.prototype.sayAge=function(){
console.log(this.age);
}
let instance1=new SubType('Ann',29);
instance1.colors.push("balck");
console.log(instance1.colors);
instance1.sayName();
instance1.sayAge();

let instance2=new SubType("Greg",27);
console.log(instance2.colors);
instance2.sayName();
instance2.sayAge();

1

原型式继承

1
2
3
4
5
6
7
8
9
10
11
12
13
//object.create()
function object(o){
function F(){};//创建一个构造函数
F.prototype=o;//构造函数的原型指向参数对象o
return new F();//返回F对象实例
}
let person={
name:"Ann",
friends:["Mary","Harry","Van"]
}
let anotherPerson=object(person);
anotherPerson.friends.push("Mike");
console.log(person.friends);// ['Mary', 'Harry', 'Van', 'Mike']

object()函数创建一个临时构造函数,将传入对象赋值给这个构造函数原型,然后返回这个临时类型的一个实例。本质上,object()是对传入的对象执行了一次浅复制,anotherperson.proto=person,如果person是构造函数,则anotherperson的[[Prototype]]将没有指向的prototype对象,也就无法通过prototype对象找到constructor进而使用construcor上面的方法和属性

这里的object函数相当与object.create()

1
2
3
4
5
6
7
8

let person={
name:"Ann",
friends:["Mary","Harry","Van"]
}
let anotherPerson=object。create(person);
anotherPerson.friends.push("Mike");
console.log(person.friends);// ['Mary', 'Harry', 'Van', 'Mike']

原型式继承适合不需要单独创建构造函数,但仍然需要在对象间共享信息的场合。

寄生式继承

与原型式继承比较接近的一种继承方式是寄生式继承

1
2
3
4
5
6
7
8
9
10
11
12
13
function createAnother(original){
let clone=Object.create(original);//通过调用函数创建一个新对象
clone.sayHi=function(){//以某种方式增强这个对象
console.log("hi");
}
return clone;//返回这个对象
}
let person={
name:"Ann",
friends:["Mary","Harry","Van"]
}
let anotherPerson=createAnother(person);
anotherPerson.sayHi();

寄生式继承同样适合主要关注对象,而不在乎类型和构造函数的场景。痛过寄生式继承给对象添加函数会导致函数难以重用,与构造函数模式类似。

寄生式组合继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
function inheritPrototype(subType,superType){//参数分别是子类和父类的构造函数
let prototype=Object.create(superType.prototype);//先复制父类的原型对象
prototype.constructor=subType;//增强对象,让新的原型对象的构造函数指向子类构造函数
subType.prototype=prototype;//赋值对象,让子类原型指向新的原型
}
function SuperType(name){
this.name=name;
this.colors=["red","blue","green"];
}
SuperType.prototype.sayName=function(){
console.log(this.name);//不能用箭头函数,因为箭头函数没有this绑定,会向上找到全局上下文
}
function SubType(name,age) {
SuperType.call(this,name);//SuperType的构造函数绑定SubType的构造函数,调用Supertype()
this.age=age;
}
inheritPrototype(SubType,SuperType);
SubType.prototype.sayAge=function(){
console.log(this.age);
}
let instance1=new SubType('Ann',29);
instance1.colors.push("balck");
console.log(instance1.colors);
instance1.sayName();
instance1.sayAge();

另一种写法:

1
2
3
4
5
6
7
8
9
10
11
12
13
function SuperType(name){
this.name=name;
this.colors=["red","blue","green"];
}
SuperType.prototype.sayName=function(){
console.log(this.name);//不能用箭头函数,因为箭头函数没有this绑定,会向上找到全局上下文
}
function SubType(name,age) {
SuperType.call(this,name);//SuperType的构造函数绑定SubType的构造函数,调用Supertype()
this.age=age;
}
SubType.prototype=Object.create(SuperType.prototype)
SubType.prototype.constructor=Subtype

寄生式组合继承基本模式:

  • 先创建父类原型的一个副本prototype
  • 给prototype设置constructor属性为subType,增强对象,解决由于重写原型导致默认constructor丢失问题
  • 将新创建的对象赋值给子类型的原型

只调用一次SuperType构造函数,效率最高