JavaScript 系列之继承(三)

296 阅读3分钟

这是我参与8月更文挑战的第15天,活动详情查看:8月更文挑战

五、寄生式继承

在内部以某种方式增强对象,最后返回对象

function createAnother(original) {
  var clone = Object(original); //通过调用函数创建一个新对象
  clone.sayHi = function () {
    //以某种方式来增强这个对象
    console.log("hi");
  };
  return clone; //返回这个对象
}
var person = {
  name: "Nicholas",
  friends: ["Shelby", "Court", "Van"],
};
var anotherPerson = createAnother(person);
anotherPerson.sayHi(); //"hi"
  • 缺点:做不到函数复用而降低效率。
  • 场景:任何能够返回新对象的函数都适用此模式。

六、寄生组合式继承

function SuperType(name) {
  this.name = name;
  this.colors = ['red', 'blue', 'green'];
}
SuperType.prototype.sayName = function() {
  console.log(this.name);
}
function SubType(name, age) {
  SuperType.call(this, name); // 第二次调用SuperType()
  this.age = age;
}
SubType.prototype = new SuperType(); // 第一次调用SuperType()
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function() {
  console.log(this.age);
}

在第一次调用 SuperType 构造函数时,SubType.prototype 会得到两个属性:name 和 colors;它们都是 SuperType 的实例属性,只不过现在位于 SubType 的原型中。当调用 SubType 构造函数时,又会调用一次 SuperType 构造函数,这一次又在新对象上创建了实例属性 name 和 colors。

image.png

如图所示,有两组 name 和 colors 属性:一组在实例上,一组在 SubType 原型中。解决这个问题的方法 —— 寄生组合继承。

寄生组合式继承:通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。 基本思路:不必为了指定子类型的原型而调用超类型的构造函数,我们所需要的无非就是超类型原型的一个副本而已。 本质上:就是使用寄生式继承来继承超类型的原型,然后再将结果指定给子类型的原型。

function inheritPrototype(subType, superType) {
  // 创建对象:创建超类型原型的一个副本对象。
  var prototype = Object(superType.prototype); 
  // 增强对象:为创建的副本添加  constructor 属性,弥补因重写原型而失去的默认的 constructor 属性。
  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);
};
function SubType(name, age) {
  SuperType.call(this, name);
  this.age = age;
}
inheritPrototype(SubType, SuperType); //实现继承
SubType.prototype.sayAge = function () {
  console.log(this.age);
};
  1. 在继承原型属性时,组合继承用原型链继承了整个父类(通过将父类实例赋值给子类构造函数的原型对象来实现),这使子类中多了一份父类的实例属性。而寄生组合式继承用原型式继承只继承了父类的原型属性(把父类构造函数的原型对象用原型式继承复制给子类的构造函数的原型对象)。
  2. 组合继承调用了两次超类型构造函数,寄生组合式继承调用了一次。
  • 优点:只调用了一次 SuperType 构造函数,避免了在 SubType.prototype 上面创建不必要的多余的属性。与此同时,原型链保持不变,且能正常使用 instanceofisPrototypeOf()

寄生组合继承是引用类型最理想的继承范式,但是由于出现的较晚,人们大多数使用的是组合继承模式。