1

我发现这篇关于 javascript 中继承的文章,我认为这是我在网上找到的最好的文章之一,但这篇文章不能用于多重继承,因为它会覆盖过去超类的原型方法和变量

ref : Javascript 继承:调用超级构造函数还是使用原型链?

我想知道是否有办法使用“代理构造函数”的原理进行多重继承(参见堆栈溢出参考帖子)。

我已经尝试过这种方法,我认为它效果很好,但我想了解其他关于限制的意见,如果有的话,关于这个实现。

你需要 jQuery 来运行它或者只使用这个 jsFiddle:http: //jsfiddle.net/NGr2L/

Function.prototype.extend = function(p_parent){ 
    function ctor() {};
    //My trick for the Multiple Inheritance is to use the jQuery.extend method
    ctor.prototype = $.extend({}, this.prototype, p_parent.prototype);
    this.prototype = new ctor();
    // I commentd this line of the reference post answer
    //because it created multiple constructor which I found confusing
    //this.prototype.constructor = this;
}

var Color = (function(){
    //Constructor
    function Color (p_color){
        //Priviligied
        this.color = p_color;
        //Private
        //...
    };

    //Public
    Color.prototype.GetFormattedColor = function(){
        return "I'm " + this.color;
    };

    return Color;
})();

var Animal = (function(){
    //Constructor
    function Animal (p_name){
        //Priviligied
        this.name = p_name;
        //Private
        //...
    };

    //Public
    Animal.prototype.GetFormattedName = function(){
        return "my name is " + this.name;
    };

    return Animal;
})();

var Tiger = (function(){
    //Constructor
    function Tiger (p_name, p_color, p_kindOfTiger){
        //Base constructor
        Color.call(this, p_color);
        Animal.call(this, p_name);

        //Priviligied
        this.kindOfTiger = p_kindOfTiger;
        //Private
        //...
    };
    //Inheritance
    Tiger.extend(Color); //I know, I could've loop 
    Tiger.extend(Animal);// on the "extend()" arguments to do this in one call

    //Public
    Tiger.prototype.GetTiger = function(){
        return "I'm a " + this.kindOfTiger + ", " + 
                                            this.GetFormattedName() + " and " + 
                                            this.GetFormattedColor()
    };

    return Tiger;
})();

var myTiger = new Tiger("Boris", "Aqua", "bengal tiger");
myTiger.GetTiger();

非常感谢

4

2 回答 2

1

实现多重继承的最佳方式是组合。

假设我们有一个类Orange扩展(继承自)类FruitColor. 这两个类中的每一个都有自己的构造函数和方法。

多重继承的主要问题是父类中的方法可能会发生冲突

function Colour(shade) {
    this.shade = shade;
}
Colour.prototype.describe = function() {
    console.log('Colour of shade', this.shade);
}

function Fruit(type) {
    this.type = type;
}
Fruit.prototype.describe = function() {
    console.log('Fruit of type', this.type);
}

function Orange() {}
Orange.prototype.describe = function() {
    this.constructor.describe(); // which describe to call?
    console.log('Orange');
}

multipleExtend(Orange, [Fruit, Colour]);

为了避免命名空间冲突,最好的办法是使用组合而不是继承

function Orange() {
    this._colour = new Colour('orange');
    this._fruit = new Fruit('orange');
}
Orange.prototype.describe = function() {
    this._colour.describe();
    this._fruit.describe();
    console.log('Orange');
}

一个解决方案的折衷可以通过扩展一个类并组合另一个类来实现——但是选择扩展哪些类以及组合哪些类可能并不实用

PS:继承和扩展的意思是一样的(防止可能的混淆)。


编辑 1

在花了一些时间研究 JS 中的多重继承的想法之后,我想出了一个抓住基本思想的设计

不幸的是,我无法将整个事情都放在 SO 答案的大小中,所以我把它写成了一篇文章。你会看到你的“代理构造函数”就是我所说的 inheritsMultipleConstructors()函数。

于 2017-10-05T04:49:29.667 回答
-1

最合适方法的决定必须反映 和的Color关系。老虎显然一种动物,动物和老虎都可能具有颜色(老虎颜色)。因此继承只适用于. A可以通过合成获得。但这里聚合将是更有利的选择。因此,该类确实包含一个类型为 的字段。AnimalTigerAnimal <= TigerColorTigercolorColor

真正的基于类的多重继承(一次直接从多个原型继承)在技术上在 JS 中是不可能的。但是基于函数的组合也是一个非常方便的工具。对于提供的示例,将有两个额外的行为,每个行为都不会意外地具有describeThyself方法名称,例如某些类实现已经在使用它。因此除了作文部分,行为也需要处理冲突的解决

为方便起见,提供的示例代码执行功能类语法...

class Color {
  constructor(colorValue) {
    this.color = colorValue;
  }
  describeThyself() {
    return `I'm colored ${this.color}.`;
  }
}

class Animal {
  constructor(speciesName) {
    this.species = speciesName;
  }
  describeThyself() {
    return `My species is called ${this.species}.`;
  }
}


function withNormalHuntingBehavior() { // function based mixin.
  function describeThyself() {
    return 'I mostly feed on herbivorous mammals.';
  }
  if (this.describeThyself) {                     // - conflict resolution
    this.describeThyself = (function (proceed) {
      return function () {                        // - function composition

        var result = proceed.apply(this/*, arguments*/);
        return (result + ' ' + describeThyself.call(this/*, result, arguments*/));
      }
    }(this.describeThyself));
  } else {
    this.describeThyself = describeThyself;
  }
  return this;
}

function withManEatingBehavior() { // function based mixin.
  function describeThyself() {
    return 'I ocassionally kill and eat humans too.';
  }
  if (this.describeThyself) {                     // - conflict resolution
    this.describeThyself = (function (proceed) {
      return function () {                        // - function composition

        var result = proceed.apply(this/*, arguments*/);
        return (result + ' ' + describeThyself.call(this/*, result, arguments*/));
      }
    }(this.describeThyself));
  } else {
    this.describeThyself = describeThyself;
  }
  return this;
}


class Tiger extends Animal {                // - inheritance part I.
  constructor(subspeciesName, colorValue) {
    super('Tiger');                         // - inheritance part II.
    this.subspecies = subspeciesName;
    this.color = (new Color(colorValue));   // - aggregation.
  }
  describeThyself() {
    return [
      super.describeThyself.call(this),     // - super delegation.
      `I'm of the "${this.subspecies}" subspecies.`,
      `And ${this.color.describeThyself()}` // - forwarding.
    ].join(' ');
  }
}
// - composition at prototype level.
withNormalHuntingBehavior.call(Tiger.prototype);


function createBengalTiger(colorValue) { // bengal tiger factory
  var
    tiger = new Tiger('Bengal Tiger', colorValue);

  // composition at instance level.
  return withManEatingBehavior.call(tiger);
}

var siberianTiger = new Tiger('Siberian Tiger', 'kind of pale orange/reddish-something');
var bengalTiger = createBengalTiger("bright reddish-gold");

console.log('siberianTiger.describeThyself() : ' + siberianTiger.describeThyself());

console.log('bengalTiger.describeThyself() : ' + bengalTiger.describeThyself());
.as-console-wrapper { max-height: 100%!important; top: 0; }

于 2018-02-04T15:20:59.997 回答