webVueBlog/mini-vue

11.手写原型式继承、寄生式继承、寄生组合式继承

webVueBlog opened this issue · 0 comments

原型式继承

function object(o) {
 function F() {}
 F.prototype = o;
 return new F();
}

在函数内部,先创建 临时性的构造函数,然后将传入的对象作为这个 构造函数的原型,最后返回这个临时构造函数的一个实例。从本质上,该函数对传入的对象执行了一次 浅拷贝。

ECMAScript 5 通过增加 Object.create()方法

这个方法接收两个参数:作为新对象原型的对象,以及给新对象定义额外属性的对象(第二个可选)

let person = {
 name: "Nicholas",
 friends: ["Shelby", "Court", "Van"]
};
let anotherPerson = Object.create(person, {
 name: {
 value: "Greg"
 }
});
console.log(anotherPerson.name); // "Greg"

场景:

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

缺点:

属性中包含的引用值始终会在相关对象间共享,跟使用原型模式是一样的。(引用类型值的属性始终都会共享相应的值,多个实例对象对引用类型的操作会被篡改。)

原型式继承是借助原型基于已有的对象创建新对象,同时还不必因此创建自定义类型。

function Person(friendship) {
  function Creator() {}
  Creator.prototype = friendship;
  return new Creator();
}

寄生式继承

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

function createAnother(original){
 let clone = object(original); // 通过调用函数创建一个新对象
 clone.sayHi = function() { // 以某种方式增强这个对象
 console.log("hi");
 };
 return clone; // 返回这个对象
} 

场景:

寄生式继承同样适合主要关注对象,而不在乎类型和构造函数的场景。(在主要考虑对象而 不是自定义类型和构造函数的情况下,寄生式继承也是一种有用的模式。)

寄生式继承(Parasitic Inheritance):创建一个仅用于封装继承过程的函数,在函数内部以某种方式增强对象

function creator(origin) {
  // 以 origin 为原型对象创建一个新对象
  let clone = Object.create(origin);

  // 以某种方式来增强这个对象
  clone.sayHi = function () {
    console.log('Hello world!');
  };

  // 返回这个对象
  return clone;
}

⚠️ 注意: 使用寄生式继承来为对象添加函数,会由于不能做到函数复用而降低效率;这一点与借用构造函数模式类似。

寄生式组合继承

寄生组合式继承,即通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。
(寄生式组合继承通过盗用构造函数继承属性,但使用混合式原型链继承方法。)

组合继承的例子:

function SubType(name, age){
 SuperType.call(this, name); // 第二次调用 SuperType()
 this.age = age;
}
SubType.prototype = new SuperType(); // 第一次调用 SuperType()
function inheritPrototype(subType, superType) {
 let prototype = object(superType.prototype); // 创建对象
 prototype.constructor = subType; // 增强对象
 subType.prototype = prototype; // 赋值对象
}

不必为了指定子类型的原型而调用超类型的构造函数,我们所需要的无非就是超类型原型的一个副本而已。 本质上,就是使用寄生式继承来继承超类型的原型,然后再将结果指定给子类型的原型。

function inherit(child, parent) {
  // 创建对象
  let prototype = Object.create(parent.prototype);

  // 增强对象
  prototype.constructor = child;

  // 指定对象
  child.prototype = prototype;
}

这个函数接收两个参数:子类型构造函数 和 超类型构造函数。

寄生式组合继承可以算是引用类型继承的最佳模式。