![]()
组合继承
组合继承,指将原型链和借用构造函数的技术组合到一块,从而发挥二者之长的一种继承模式。其背后思路使用用原型链实现对原型属性和方法的继承,而通过构造函数来实现对实例属性的继承。这样,即通过在原型上定义方法实现了函数复用,又能够保证每个实例都有它自己的属性。
下面来看一个例子
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 27 28 29 30 31 32 33
| function SuperType(name) { this.name = name; this.color = ['red', 'blue', 'green']; };
SuperType.prototype.sayName = function() { console.log(this.name); };
function SubType(name, age) { SuperType.call(this, name);
this.age = age; };
SubType.prototype = new SuperType(); console.log(SubType.prototype.constructor); SubType.prototype.constructor = SubType; SubType.prototype.sayAge = function() { console.log(this.age); };
var instance1 = new SubType('Jake', 20) instance1.color.push('black'); console.log(instance1.color); instance1.sayName(); instance1.sayAge();
var instance2 = new SubType('Greg', 21); console.log(instance2.color); instance2.sayName(); instance2.sayAge();
|
观察输出结果,便可以发现:两个SubType实例(instance1
和instance2
)既分别有自己的属性,又可以使用相同的方法。
优点
组合继承避免了原型链和借用构造函数的缺陷,融合了它们的优点,所以是JS中最常用的继承模式。而且,instanceof
和isPrototypeOf()
也能够用于识别基于组合继承创建的对象。
缺点
- 调用两次SuperType构造函数
- 在SubType.prototype上创建了不必要的属性
寄生组合继承
寄生组合继承
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', 'yellow'] }
SuperType.prototype.sayName = function () { console.log(this.name) }
function SubType (name, age) { SuperType.call(this, name) this.age = age }
SubType.prototype = Object.create(SuperType.prototype) SubType.prototype.constructor = SubType
SubType.prototype.sayAge = function () { console.log(this.age) }
let obj = new SubType('jake', 22) obj.sayName() obj.sayAge() console.log(obj instanceof SubType) console.log(obj instanceof SuperType)
|
优点
- 寄生组合继承只调用了一次SuperType,所以更高效
- 避免了在SubType.prototype上创建了不必要的属性
下面说说原型链和构造函数的缺点
原型链
缺点:当原型链中包含引用类型值时,原型属性会被所有实例共享;
下面看一个例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| function SuperType() { this.color = ['red', 'blue', 'green']; }
function SubType() {};
SubType.prototype = new SuperType();
var instance1 = new SubType(); instance1.color.push('black'); console.log(instance1.color);
var instance2 = new SubType(); console.log(instance2.color);
|
借用构造函数
缺点:如果仅仅使用构造函数,方法都在构造函数中定义,因此函数就无法实现复用了。而且,在超类型的原型中定义的方法,对于子类型而言也是不可见的。