JS - 寄生式 & 寄生式组合继承【继承篇】

136 阅读2分钟

组合继承(即构盗用造函数+子类原型重写为父类的实例)有效率问题,调用了两次构造函数

寄生式组合继承通过盗用构造函数继承属性,但使用混合式原型链继承方法,基本思路是在不通过调用父类构造函数给子类原型赋值情况下,获得父类原型的副本(就是使用寄生式来继承父类原型),然后将返回的新对象赋值给子类原型。

寄生式继承

与原型式继承比较接近的一种继承方式,寄生式继承背后的思路类似于寄生构造函数和工厂模式:创建一个实现继承的函数,以某种方式增强对象,然后返回这个对象

寄生式继承的弊端: 通过寄生式继承给对象添加函数会导致函数难以重用

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