组合继承(即构盗用造函数+子类原型重写为父类的实例)有效率问题,调用了两次构造函数
寄生式组合继承通过盗用构造函数继承属性,但使用混合式原型链继承方法,基本思路是在不通过调用父类构造函数给子类原型赋值情况下,获得父类原型的副本(就是使用寄生式来继承父类原型),然后将返回的新对象赋值给子类原型。
寄生式继承
与原型式继承比较接近的一种继承方式,寄生式继承背后的思路类似于寄生构造函数和工厂模式:创建一个实现继承的函数,以某种方式增强对象,然后返回这个对象
寄生式继承的弊端: 通过寄生式继承给对象添加函数会导致函数难以重用
const createInherit = (original) => {
// 创建一个新对象, 可以是 deepClone(original),此处仅仅潜伏值
const clone = {...original};
// 以某种方式增强这个对象
clone.sayHi = () => log("hi");
// 返回这个对象
return clone;
};
const parent = {
name: "Nicholas",
friends: ["Wendeer", "Yohan"],
};
// 基于 parent 对象返回一个新对象,新返回的对象具有 parent 的所有属性和方法,还有一个新方法叫 sayHi
// son 是寄生在 parent 上的
const son = createInherit(parent);
son.sayHi(); // log: hi
寄生式组合继承
寄生式组合继承通过盗用构造函数继承属性,但使用混合式原型链继承方法。不通过调用父类构造函数给子类原型赋值,而是取得父类原型的一个副本(使用寄生式继承来继承父类的原型)然后将返回的新对象给子类原型
寄生式组合继承的基本模式如下,原型链仍然保持不变, instanceof 操作符 正常有效,寄生式组合继承可以算是引用类型的最佳模式
const createShadow = (obj) => ({ ...obj });
/**
* 寄生式组合继承的核心逻辑
* @param {Function} SonCtor 子类构造函数
* @param {Function} ParentCtor 父类构造函数
*/
function parasiticAssociation(SonCtor, ParentCtor) {
// 创建父类原型的一个副本,使用寄生式来货得父类原型的一个副本
const prototype = createShadow(ParentCtor.prototype);
// 解决重写原型导致 constructor 指向的问题
prototype.constructor = SonCtor;
// 将新原型赋值给 子类的 原型
SonCtor.prototype = prototype;
}
function Parent(name) {
this.name = name;
this.colors = ["red", "green", "purple"];
}
Parent.prototype.sayHi = function () {
log(`Hi, I'm ${this.name}`);
};
function Son(name, age) {
Parent.call(this, name);
this.age = age;
}
// 寄生式组合继承
parasiticAssociation(Son, Parent);
Son.prototype.sayHi = function () {
log(`Helo, I'm ${this.name}, ${this.age}`);
};
const son = new Son("kj", 23);
son.sayHi(); // Helo, I'm kj, 23