寄生组合式继承笔记

2018-12-30  本文已影响0人  potato865

组合式继承的不足

组合继承是JavaScript最常用的继承模式,但也有它的不足:

  1. 无论什么情况下,都会调用两次超类构造函数
  2. 子类会包含超类对象全部的实例属性,但又不得不在调用子类构造函数时重写这些属性

先看一看组合继承的例子:

  function SuperType(name){
    this.name = name;
    this.colors = ["red", "blue", "green"];
  }
  SuperType.prototype.sayName = function(){
   alert(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(){
    alert(this.age);
  };

如代码所示,

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

解决方案

有两组 name 和 colors 属性:一组在实例上,一组在 SubType 原型中,这是不合理的。解决这个问题方法是:寄生组合式继承。

寄生组合式继承基本模式:

function inheritPrototype(subType, superType){
  var prototype = object(superType.prototype); //创建对象
  prototype.constructor = subType; //增强对象
  subType.prototype = prototype; //指定对象
}

这个函数接收两个参数:子类型构造函数和超类型构造函数, 执行以下步骤:

  1. 第一步是创建超类型原型的一个副本。
  2. 为创建的副本添加 constructor 属性,从而弥补因重写原型而失去的默认的 constructor 属性。
  3. 将新创建的对象(即副本)赋值给子类型的原型。

现在我们就可以用调用 inheritPrototype() 函数的语句,去替换前面例子中为子类型原型赋值的语句了,修改后的代码如下:

function SuperType(name){
  this.name = name;
  this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function(){
  alert(this.name);
};
function SubType(name, age){
  SuperType.call(this, name);
  this.age = age;
}
inheritPrototype(SubType, SuperType);
  SubType.prototype.sayAge = function(){
  alert(this.age);
};

这个例子的高效率体现在它只调用了一次 SuperType 构造函数,并且因此避免了在 SubType.prototype 上面创建不必要的、多余的属性。与此同时,原型链还能保持不变;因此,还能够正常使用instanceof 和 isPrototypeOf() 。普遍认为寄生组合式继承是引用类型最理想的继承范式。

上一篇 下一篇

猜你喜欢

热点阅读