Multiple Inheritance

As of July 2017, there is no native support for multiple inheritance. We can, however, implement 'mix-ins':


//(continues from the example in 8.6.3)
var MixedDalmatian = Base => class extends Base {
  jump() {
    console.log(this.name + ' jumped.');
  }

  *bark() { // to override bark() in GermanShepherd
    while (true) {
      console.log('wok');
      yield;
    }
  }
};

class Dalmatian extends MixedDalmatian(Dog) {} // pure breed
class DalShepherd extends MixedDalmatian(GermanShepherd) {} // a crossbreed!

var p = new Dalmatian('Spotty', 7, 'White');
p.jump();

var m = new DalShepherd('Mixy', 6, 'Grey');
m.jump();

var mb = m.bark();
mb.next();
m.sleep();

Spotty jumped. Mixy jumped. wok Mixy has fallen asleep. Mixy seems to have awaken. When will Mixy sleep again?

We can also define a standard class aggregation function:


var aggregation = (baseClass, ...mixins) => {
  class base extends baseClass {
    constructor(...args) {
      super(...args);
      mixins.forEach((mixin) => {
        copyProps(this, (new mixin));
      });
    }
  }

  let copyProps = (target, source) => { // this function copies all properties and symbols, filtering out some special ones
    Object.getOwnPropertyNames(source)
      .concat(Object.getOwnPropertySymbols(source))
      .forEach((prop) => {
        if (!prop.match(/^(?:constructor|prototype|arguments|caller|name|bind|call|apply|toString|length)$/)) {
          Object.defineProperty(target, prop, Object.getOwnPropertyDescriptor(source, prop));
        }
      });
  };

  mixins.forEach((mixin) => { // outside contructor() to allow aggregation(A,B,C).staticFunction() to be called etc.
    copyProps(base.prototype, mixin.prototype);
    copyProps(base, mixin);
  });

  return base;
};

class Person {
  constructor(n) {
    this.name = n;
  }
}

class Male {
  constructor(s = 'male') {
    this.sex = s;
  }
}

class Child {
  constructor(a = 12) {
    this.age = a;
  }

  tellAge() {
    console.log(this.name + ' is ' + this.age + ' years old.');
  }
}

class Boy extends aggregation(Person, Male, Child) {}

var m = new Boy('Mike');
m.tellAge();

Mike is 12 years old.

The aggregation function above requires the use of default parameters in the constructors of the subsequent classes in the class list. Furthermore, it will prefer properties and methods of a class that appears later in the class list, when there are duplicate names.