[javascript] ES6 Class Multiple inheritance

I've done most of my research on this on BabelJS and on MDN (which has no information at all), but please feel free to tell me if I have not been careful enough in looking around for more information about the ES6 Spec.

I'm wondering whether or not ES6 supports multiple inheritance in the same fashion as other duck-typed languages do. For instance, can I do something like:

class Example extends ClassOne, ClassTwo {
    constructor() {
    }
}

to extend multiple classes on to the new class? If so, will the interpreter prefer methods/properties from ClassTwo over ClassOne?

This question is related to javascript ecmascript-6

The answer is


As a proof of concept, I did the following function. It takes a list of classes and composes them into a new class (the last prototype wins so there are no conflicts). When creating a composed function, the user can choose to use all original constructors [sic!] or pass their own. This was the biggest challenge of this experiment: to come up with a description of what constructor should do. Copying methods into a prototype is not an issue but what's the intended logic of newly composed object. Or maybe it should be constructorless? In Python, from what I know, it finds the matching constructor but functions in JS are more accepting, hence one can pass to a function just about everything and from signature it won't be clear.

I don't think it's optimised but the purpose was exploring possibilities. instanceof will not behave as expected which, I guess, is a bummer, since class-oriented developers like to use this as a tool.

Maybe JavaScript just doesn't have it.

_x000D_
_x000D_
/*_x000D_
    (c) Jon Krazov 2019_x000D_
_x000D_
    Below is an experiment searching boundaries of JavaScript._x000D_
    It allows to compute one class out of many classes._x000D_
_x000D_
    Usage 1: Without own constructor_x000D_
_x000D_
    If no constructor is passed then constructor of each class will be called_x000D_
    with params passed in object. In case of missing params, constructor_x000D_
    will be called without params._x000D_
_x000D_
    Example:_x000D_
_x000D_
    const MyClass1 = computeClass([Class1, Class2, Class3]);_x000D_
    const myClass1Instance = new MyClass1({_x000D_
        'Class1': [1, 2],_x000D_
        'Class2': ['test'],_x000D_
        'Class3': [(value) => value],_x000D_
    });_x000D_
_x000D_
    Usage 2: With own constructor_x000D_
_x000D_
    If constructor is passed in options object (second param) then it will_x000D_
    be called in place of constructors of all classes._x000D_
_x000D_
    Example:_x000D_
_x000D_
    const MyClass2 = computeClass([Class1, Class2, Class3], {_x000D_
        ownConstructor(param1) {_x000D_
            this.name = param1;_x000D_
        }_x000D_
    });_x000D_
    const myClass2Instance = new MyClass2('Geoffrey');_x000D_
*/_x000D_
_x000D_
// actual function_x000D_
_x000D_
var computeClass = (classes = [], { ownConstructor = null } = {}) => {_x000D_
    const noConstructor = (value) => value != 'constructor';_x000D_
_x000D_
    const ComputedClass = ownConstructor === null_x000D_
        ? class ComputedClass {_x000D_
            constructor(args) {_x000D_
                classes.forEach((Current) => {_x000D_
                    const params = args[Current.name];_x000D_
_x000D_
                    if (params) {_x000D_
                        Object.assign(this, new Current(...params));_x000D_
                    } else {_x000D_
                        Object.assign(this, new Current());_x000D_
                    }_x000D_
                })_x000D_
            }_x000D_
        }_x000D_
        : class ComputedClass {_x000D_
            constructor(...args) {_x000D_
                if (typeof ownConstructor != 'function') {_x000D_
                    throw Error('ownConstructor has to be a function!');_x000D_
                }_x000D_
                ownConstructor.call(this, ...args);_x000D_
            } _x000D_
        };_x000D_
_x000D_
    const prototype = classes.reduce(_x000D_
        (composedPrototype, currentClass) => {_x000D_
            const partialPrototype = Object.getOwnPropertyNames(currentClass.prototype)_x000D_
                .reduce(_x000D_
                    (result, propName) =>_x000D_
                        noConstructor(propName)_x000D_
                            ? Object.assign(_x000D_
                                    result,_x000D_
                                    { [propName]: currentClass.prototype[propName] }_x000D_
                                )_x000D_
                            : result,_x000D_
                    {}_x000D_
                );_x000D_
_x000D_
            return Object.assign(composedPrototype, partialPrototype);_x000D_
        },_x000D_
        {}_x000D_
    );_x000D_
_x000D_
    Object.entries(prototype).forEach(([prop, value]) => {_x000D_
 Object.defineProperty(ComputedClass.prototype, prop, { value });_x000D_
    });_x000D_
    _x000D_
    return ComputedClass;_x000D_
}_x000D_
_x000D_
// demo part_x000D_
_x000D_
var A = class A {_x000D_
    constructor(a) {_x000D_
        this.a = a;_x000D_
    }_x000D_
    sayA() { console.log('I am saying A'); }_x000D_
}_x000D_
_x000D_
var B = class B {_x000D_
    constructor(b) {_x000D_
        this.b = b;_x000D_
    }_x000D_
    sayB() { console.log('I am saying B'); }_x000D_
}_x000D_
_x000D_
console.log('class A', A);_x000D_
console.log('class B', B);_x000D_
_x000D_
var C = computeClass([A, B]);_x000D_
_x000D_
console.log('Composed class');_x000D_
console.log('var C = computeClass([A, B]);', C);_x000D_
console.log('C.prototype', C.prototype);_x000D_
_x000D_
var c = new C({ A: [2], B: [32] });_x000D_
_x000D_
console.log('var c = new C({ A: [2], B: [32] })', c);_x000D_
console.log('c instanceof A', c instanceof A);_x000D_
console.log('c instanceof B', c instanceof B);_x000D_
_x000D_
console.log('Now c will say:')_x000D_
c.sayA();_x000D_
c.sayB();_x000D_
_x000D_
console.log('---');_x000D_
_x000D_
var D = computeClass([A, B], {_x000D_
    ownConstructor(c) {_x000D_
        this.c = c;_x000D_
    }_x000D_
});_x000D_
_x000D_
console.log(`var D = computeClass([A, B], {_x000D_
    ownConstructor(c) {_x000D_
        this.c = c;_x000D_
    }_x000D_
});`);_x000D_
_x000D_
var d = new D(42);_x000D_
_x000D_
console.log('var d = new D(42)', d);_x000D_
_x000D_
console.log('Now d will say:')_x000D_
d.sayA();_x000D_
d.sayB();_x000D_
_x000D_
console.log('---');_x000D_
_x000D_
var E = computeClass();_x000D_
_x000D_
console.log('var E = computeClass();', E);_x000D_
_x000D_
var e = new E();_x000D_
_x000D_
console.log('var e = new E()', e);
_x000D_
_x000D_
_x000D_

Originally posted here (gist.github.com).


There is no easy way to do multiple class inheritance. I follow the combination of association and inheritance to achieve this kind of behavior.

    class Person {
        constructor(firstname, lastname, age){
            this.firstname = firstname,
            this.lastname = lastname
            this.Age = age
        }

        fullname(){
                return this.firstname +" " + this.lastname;
            } 
    }

    class Organization {
        constructor(orgname){
            this.orgname = orgname;
        }
    }

    class Employee extends Person{
        constructor(firstname, lastname, age,id) {
            super(firstname, lastname, age);
            this.id = id;
        }

    }
    var emp = new Employee("John", "Doe", 33,12345);
    Object.assign(emp, new Organization("Innovate"));
    console.log(emp.id);
    console.log(emp.orgname);
    console.log(emp.fullname());

Hope this is helpful.


I will add my solution as well - I found it the most friendly for myself from what I read in this thread.

export const aggregate = (...mixins) => (Base) => {
  const copyProps = (target, source) => {
    Object.getOwnPropertyNames(source)
      .concat(Object.getOwnPropertySymbols(source))
      .forEach((prop) => {
        if (prop.match(/^(?:constructor|prototype|arguments|caller|name|bind|call|apply|toString|length)$/)) {
          return;
        }
        Object.defineProperty(target, prop, Object.getOwnPropertyDescriptor(source, prop));
      });
  };
  mixins.forEach((mixin) => {
    copyProps(Base, mixin);
    copyProps(Base.prototype, mixin.prototype);
  });
  return Base;
};

You can use it then like this:

class _MyBaseClass {}
const MyBaseClass = aggregate(ExtensionOne, ExtensionTwo)(_MyBaseClass);

use extent with custom function to handle multiple inheritance with es6

_x000D_
_x000D_
var aggregation = (baseClass, ...mixins) => {_x000D_
    let base = class _Combined extends baseClass {_x000D_
        constructor (...args) {_x000D_
            super(...args)_x000D_
            mixins.forEach((mixin) => {_x000D_
                mixin.prototype.initializer.call(this)_x000D_
            })_x000D_
        }_x000D_
    }_x000D_
    let copyProps = (target, source) => {_x000D_
        Object.getOwnPropertyNames(source)_x000D_
            .concat(Object.getOwnPropertySymbols(source))_x000D_
            .forEach((prop) => {_x000D_
            if (prop.match(/^(?:constructor|prototype|arguments|caller|name|bind|call|apply|toString|length)$/))_x000D_
                return_x000D_
            Object.defineProperty(target, prop, Object.getOwnPropertyDescriptor(source, prop))_x000D_
        })_x000D_
    }_x000D_
    mixins.forEach((mixin) => {_x000D_
        copyProps(base.prototype, mixin.prototype)_x000D_
        copyProps(base, mixin)_x000D_
    })_x000D_
    return base_x000D_
}_x000D_
_x000D_
class Colored {_x000D_
    initializer ()     { this._color = "white" }_x000D_
    get color ()       { return this._color }_x000D_
    set color (v)      { this._color = v }_x000D_
}_x000D_
_x000D_
class ZCoord {_x000D_
    initializer ()     { this._z = 0 }_x000D_
    get z ()           { return this._z }_x000D_
    set z (v)          { this._z = v }_x000D_
}_x000D_
_x000D_
class Shape {_x000D_
    constructor (x, y) { this._x = x; this._y = y }_x000D_
    get x ()           { return this._x }_x000D_
    set x (v)          { this._x = v }_x000D_
    get y ()           { return this._y }_x000D_
    set y (v)          { this._y = v }_x000D_
}_x000D_
_x000D_
class Rectangle extends aggregation(Shape, Colored, ZCoord) {}_x000D_
_x000D_
var rect = new Rectangle(7, 42)_x000D_
rect.z     = 1000_x000D_
rect.color = "red"_x000D_
console.log(rect.x, rect.y, rect.z, rect.color)
_x000D_
_x000D_
_x000D_


Well Object.assign gives you the possibility to do something close albeit a bit more like composition with ES6 classes.

class Animal {
    constructor(){ 
     Object.assign(this, new Shark()) 
     Object.assign(this, new Clock()) 
  }
}

class Shark {
  // only what's in constructor will be on the object, ence the weird this.bite = this.bite.
  constructor(){ this.color = "black"; this.bite = this.bite }
  bite(){ console.log("bite") }
  eat(){ console.log('eat') }
}

class Clock{
  constructor(){ this.tick = this.tick; }
  tick(){ console.log("tick"); }
}

let animal = new Animal();
animal.bite();
console.log(animal.color);
animal.tick();

I've not seen this used anywhere but it's actually quite useful. You can use function shark(){} instead of class but there are advantages of using class instead.

I believe the only thing different with inheritance with extend keyword is that the function don't live only on the prototype but also the object itself.

Thus now when you do new Shark() the shark created has a bite method, while only its prototype has a eat method


My answer seems like less code and it works for me:

_x000D_
_x000D_
    class Nose {
      constructor() {
        this.booger = 'ready'; 
      }
      
      pick() {
        console.log('pick your nose')
      } 
    }
    
    class Ear {
      constructor() {
        this.wax = 'ready'; 
      }
      
      dig() {
        console.log('dig in your ear')
      } 
    }
    
    class Gross extends Classes([Nose,Ear]) {
      constructor() {
        super();
        this.gross = true;
      }
    }
    
    function Classes(bases) {
      class Bases {
        constructor() {
          bases.forEach(base => Object.assign(this, new base()));
        }
      }
      bases.forEach(base => {
        Object.getOwnPropertyNames(base.prototype)
        .filter(prop => prop != 'constructor')
        .forEach(prop => Bases.prototype[prop] = base.prototype[prop])
      })
      return Bases;
    }

    
    // test it
    
    var grossMan = new Gross();
    grossMan.pick(); // eww
    grossMan.dig();  // yuck!
_x000D_
_x000D_
_x000D_


I'v come up with these solution:

'use strict';

const _         = require( 'lodash' );

module.exports  = function( ParentClass ) {

    if( ! ParentClass ) ParentClass = class {};

    class AbstractClass extends ParentClass {
        /**
         * Constructor
        **/
        constructor( configs, ...args ) {
            if ( new.target === AbstractClass )
                throw new TypeError( "Cannot construct Abstract instances directly" );

            super( args );

            if( this.defaults === undefined )
                throw new TypeError( new.target.name + " must contain 'defaults' getter" );

            this.configs = configs;
        }
        /**
         * Getters / Setters
        **/
        // Getting module configs
        get configs() {
            return this._configs;
        }
        // Setting module configs
        set configs( configs ) {
            if( ! this._configs ) this._configs = _.defaultsDeep( configs, this.defaults );
        }
    }

    return AbstractClass;
}

usage:

const EventEmitter  = require( 'events' );
const AbstractClass = require( './abstracts/class' )( EventEmitter );

class MyClass extends AbstractClass {
    get defaults() {
        return {
            works: true,
            minuses: [
                'u can have only 1 class as parent wich was\'t made by u',
                'every othere classes should be your\'s'
            ]
        };
    }
}

As long as you'r making these trick with your customly writen classes it can be chained. but us soon as u want to extend some function/class written not like that - you will have no chance to continue loop.

const EventEmitter  = require( 'events' );
const A = require( './abstracts/a' )(EventEmitter);
const B = require( './abstracts/b' )(A);
const C = require( './abstracts/b' )(B);

works for me in node v5.4.1 with --harmony flag


https://www.npmjs.com/package/ts-mixer

With the best TS support and many other useful features!


The solution below (class cloning by copying the instance fields and prototype properties) works for me. I am using normal JS (i.e. not Typescript), with JsDoc annotations and VSCode for compile-time type checking.

The solution interface is very simple:

class DerivedBase extends cloneClass(Derived, Base) {}

//To add another superclass:
//class Der1Der2Base extends cloneClass(Derived2, DerivedBase)

let o = new DerivedBase()  

The classes involved can be created just like normal ES6 classes.

However the following needs to be done:

  • Use isInstanceOf() instead of the builtin operator instanceof.
  • Instead of using 'super' to call non-constructor members of the base class, use the function super2() instead.
  • Don't write any code in the constructors, instead write it in a class method called 'init()' that is in turn called by the constructor. See the example below.
/* Paste the entire following text into the browser's dev console */
/* Tested on latest version of Chrome, Microsoft Edge and FireFox (Win OS)*/
/* Works with JSDoc in VSCode */
/* Not tested on minified/obfuscated code */

//#region library

const log = console.log

/**
 * abbreviation for Object.getPrototypeOf()
 * @param {any} o
 */
function proto(o) { return Object.getPrototypeOf(o) }

/** @param {function} fn */
function callIfNonNull(fn) { if (fn != null) { return fn() } }

/**
 * @param {boolean} b
 * @param {()=>string} [msgFn]
 */
function assert(b, msgFn) {
    if (b) { return }
    throw new Error('assert failed: ' + ((msgFn == null) ? '' : msgFn()))
}

/** @param {any} o */
function asAny(o) { return o }

/**
 * Use this function instead of super.<functionName>
 * @param {any} obj
 * @param {string} attr the name of the function/getter/setter
 * @param {any} cls the class for the current method
 * @param {any[]} args arguments to the function/getter/setter
 */
function super2(obj, attr, cls, ...args) {
    let nms = clsNms(obj)
    assert(nms[0] == nms[1])
    const objCls = proto(obj)
    const superObj = proto(ancestorNamed(objCls, cls.name))
    assert(superObj != obj)
    const attrDscr = getOwnOrBasePropDscr(superObj, attr)
    if (attrDscr == null) { return null }
    let attrVal = attrDscr['value']
    const attrGet = attrDscr['get']
    const attrSet = attrDscr['set']
    if (attrVal == null) {
        if (attrGet != null) {
            if (attrSet != null) {
                assert([0, 1].includes(args.length))
                attrVal = ((args.length == 0) ? attrGet : attrSet)
            } else {
                assert(args.length == 0,
                    () => 'attr=' + attr + ', args=' + args)
                attrVal = attrGet
            }
        } else if (attrSet != null) {
            assert(args.length == 1)
            attrVal = attrSet
        } else {
            assert(false)//no get or set or value!!!!
        }
        assert(typeof attrVal == 'function')
    }
    if (typeof attrVal != 'function') { return attrVal }
    const boundFn = attrVal.bind(obj)
    return boundFn(...args)
}

/**
 * Use this function to call own prop instead of overriden prop
 * @param {any} obj
 * @param {string} attr the name of the function/getter/setter
 * @param {any} cls the class for the current method
 * @param {any[]} args arguments to the function/getter/setter
 */
function ownProp(obj, attr, cls, ...args) {
    let protoObj = ancestorNamed(proto(obj), cls.name)
    const attrDscr = Object.getOwnPropertyDescriptor(protoObj, attr)
    if (attrDscr == null) {
        log(`ownProp(): own property '${attr}' does not exist...`)
        return null
    }
    let attrVal = attrDscr['value']
    const attrGet = attrDscr['get']
    const attrSet = attrDscr['set']
    if (attrVal == null) {
        if (attrGet != null) {
            if (attrSet != null) {
                assert([0, 1].includes(args.length))
                attrVal = ((args.length == 0) ? attrGet : attrSet)
            } else {
                assert(args.length == 0,
                    () => 'attr=' + attr + ', args=' + args)
                attrVal = attrGet
            }
        } else if (attrSet != null) {
            assert(args.length == 1)
            attrVal = attrSet
        } else {
            assert(false)//no get or set or value!!!!
        }
        assert(typeof attrVal == 'function')
    }
    if (typeof attrVal != 'function') {
        log(`ownProp(): own property '${attr}' not a fn...`)
        return attrVal
    }
    const boundFn = attrVal.bind(obj)
    return boundFn(...args)
}

/**
 * @param {any} obj
 * @param {string} nm
 */
function getOwnOrBasePropDscr(obj, nm) {
    let rv = Object.getOwnPropertyDescriptor(obj, nm)
    if (rv != null) { return rv }
    let protObj = proto(obj)
    if (protObj == null) { return null }
    return getOwnOrBasePropDscr(protObj, nm)
}

/**
 * @param {any} obj
 * @param {string} nm
 */
function ancestorNamed(obj, nm) {
    const ancs = ancestors(obj)
    for (const e of ancs) {
        if ((e.name || e.constructor.name) == nm) { return e }
    }
}

/**
 * @template typeOfDerivedCls
 * @template typeOfBaseCls
 * @param {typeOfDerivedCls} derivedCls
 * @param {typeOfBaseCls} baseCls
 * @returns {typeOfDerivedCls & typeOfBaseCls}
 */
function cloneClass(derivedCls, baseCls) {
    const derClsNm = derivedCls['name'], baseClsNm = baseCls['name']
    const gbl = globalThis

    //prevent unwanted cloning and circular inheritance:
    if (isInstanceOf(baseCls, asAny(derivedCls))) { return asAny(baseCls) }
    if (isInstanceOf(derivedCls, asAny(baseCls))) { return asAny(derivedCls) }

    //Object does not derive from anything; it is the other way round:
    if (derClsNm == 'Object') { return cloneClass(baseCls, derivedCls) }

    //use cached cloned classes if available
    if (gbl.clonedClasses == null) { gbl.clonedClasses = {} }
    const k = derClsNm + '_' + baseClsNm, kVal = gbl.clonedClasses[k]
    if (kVal != null) { return kVal }

    //clone the base class of the derived class (cloning occurs only if needed)
    let derBase = cloneClass(proto(derivedCls), baseCls)

    //clone the derived class

    const Clone = class Clone extends derBase {

        /**  @param {any[]} args */
        constructor(...args) {
            super(...args)
            ownProp(this, 'init', Clone, ...args)
        }
    }

    //clone the properties of the derived class
    Object.getOwnPropertyNames(derivedCls['prototype'])
        .filter(prop => prop != 'constructor')
        .forEach(prop => {
            const valToSet =
                Object.getOwnPropertyDescriptor(derivedCls['prototype'], prop)
            if (typeof valToSet == 'undefined') { return }
            Object.defineProperty(Clone.prototype, prop, valToSet)
        })

    //set the name of the cloned class to the same name as its source class:
    Object.defineProperty(Clone, 'name', { value: derClsNm, writable: true })

    //cache the cloned class created
    gbl.clonedClasses[k] = Clone
    log('Created a cloned class with id ' + k + '...')
    return asAny(Clone)
}

/**
 * don't use instanceof throughout your application, use this fn instead
 * @param {any} obj
 * @param {Function} cls
 */
function isInstanceOf(obj, cls) {
    if (obj instanceof cls) { return true }
    return clsNms(obj).includes(cls.name)
}

/** @param {any} obj */
function clsNms(obj) {
    return ancestors(obj).map(/** @param {any} e */ e =>
        e.name || e.constructor.name)
}

/**
 * From: https://gist.github.com/ceving/2fa45caa47858ff7c639147542d71f9f
 * Returns the list of ancestor classes.
 *
 * Example:
 *   ancestors(HTMLElement).map(e => e.name || e.constructor.name)
 *   => ["HTMLElement", "Element", "Node", "EventTarget", "Function", "Object"]
 * @param {any} anyclass
 */
function ancestors(anyclass) {
    if (anyclass == null) { return [] }
    return [anyclass, ...(ancestors(proto(anyclass)))]
}

//#endregion library

//#region testData
class Base extends Object {

    /** @param {any[]} args */
    constructor(...args) {//preferably accept any input
        super(...args)
        ownProp(this, 'init', Base, ...args)
    }

    /** @param {any[]} _args */
    init(..._args) {
        log('Executing init() of class Base...')
        //TODO: add code here to get the args as a named dictionary

        //OR, follow a practice of parameterless constructors and
        //initial-value-getting methods for class field intialization

        /** example data field of the base class */
        this.baseClsFld = 'baseClsFldVal'
    }

    m1() { log('Executed base class method m1') }

    b1() { log('Executed base class method b1') }

    get baseProp() { return 'basePropVal' }
}

class Derived extends Object {//extend Object to allow use of 'super'

    /** @param {any[]} args */
    constructor(...args) {//convention: accept any input
        super(...args)
        ownProp(this, 'init', Derived, ...args)
    }

    /** @param {any[]} _args */
    init(..._args) {
        log('Executing init() of class Derived...')
        this.derClsFld = 'derclsFldVal'
    }

    m1() {
        const log = /** @param {any[]} args */(...args) =>
            console.log('Derived::m1(): ', ...args)
        log(`super['m1']: `, super['m1'])
        super2(this, 'm1', Derived)

        log(`super['baseProp']`, super['baseProp'])

        log(`super2(this, 'baseProp', Derived)`,
            super2(this, 'baseProp', Derived))

        log(`super2(this, 'nonExistentBaseProp', Derived)`,
            super2(this, 'nonExistentBaseProp', Derived))
    }

    m2() {
        log('Executed derived class method 2')
    }
}

class DerivedBase extends cloneClass(Derived, Base) {

    /** @param {any[]} args */
    constructor(...args) {
        super(...args)
        ownProp(this, 'init', DerivedBase, ...args)
    }

    /** @param {any[]} _args */
    init(..._args) {
        log('Executing init() of class DerivedBase...')
    }
}

log('Before defining o (object of DerivedBase)...')
let o = new DerivedBase()
log('After defining o (object of DerivedBase)...')

class Derived2 extends Base {

    /** @param {any} args */
    constructor(...args) {
        //convention/best practice: use passthrough constructors for the classes
        //you write
        super(...args)
        ownProp(this, 'init', Derived2, ...args)
    }

    /**
     * @param {any[]} _args
     */
    init(..._args) {
        log('Executing init() of class Derived2...')
    }

    derived2func() { log('Executed Derived2::derived2func()') }
}

class Der1Der2Base extends cloneClass(Derived2, DerivedBase) {

    /** @param {any} args */
    constructor(...args) {
        //convention/best practice: use passthrough constructors for the classes
        //you write
        super(...args)
        ownProp(this, 'init', Der1Der2Base, ...args)
    }

    /** @param {any[]} _args */
    init(..._args) {
        log('Executing original ctor of class Der1Der2Base...')
    }

}

log('Before defining o2...')
const o2 = new Der1Der2Base()
log('After defining o2...')

class NotInInheritanceChain { }
//#endregion testData

log('Testing fields...')
log('o.derClsFld:', o.derClsFld)
log('o.baseClsFld:', o.baseClsFld)
//o.f3  JSDoc gives error in VSCode

log('Test method calls')
o.b1()
o.m1()
o.m2()
//o.m3() //JSDoc gives error in VSCode
log('Test object o2')
o2.b1()
o2.m1()
o2.derived2func()

//don't use instanceof throughout your application, use this fn instead
log('isInstanceOf(o,DerivedBase)', isInstanceOf(o, DerivedBase))
log('isInstanceOf(o,Derived)', isInstanceOf(o, Derived))
log('isInstanceOf(o,Base)', isInstanceOf(o, Base))

log('isInstanceOf(o,NotInInheritanceChain)',
    isInstanceOf(o, NotInInheritanceChain))

A note of caution: the JSDoc intersection operator & may not always work. In that case some other solution may need to be used. For example, a separate interface class may need to be defined that will 'manually' combine the 2 classes. This interface class can extend from one of the classes and the other class's interface can be automatically implemented using VsCode quick fix option.


Check my example below, super method working as expected. Using a few tricks even instanceof works (most of the time):

// base class
class A {  
  foo() {
    console.log(`from A -> inside instance of A: ${this instanceof A}`);
  }
}

// B mixin, will need a wrapper over it to be used
const B = (B) => class extends B {
  foo() {
    if (super.foo) super.foo(); // mixins don't know who is super, guard against not having the method
    console.log(`from B -> inside instance of B: ${this instanceof B}`);
  }
};

// C mixin, will need a wrapper over it to be used
const C = (C) => class extends C {
  foo() {
    if (super.foo) super.foo(); // mixins don't know who is super, guard against not having the method
    console.log(`from C -> inside instance of C: ${this instanceof C}`);
  }
};

// D class, extends A, B and C, preserving composition and super method
class D extends C(B(A)) {  
  foo() {
    super.foo();
    console.log(`from D -> inside instance of D: ${this instanceof D}`);
  }
}

// E class, extends A and C
class E extends C(A) {
  foo() {
    super.foo();
    console.log(`from E -> inside instance of E: ${this instanceof E}`);
  }
}

// F class, extends B only
class F extends B(Object) {
  foo() {
    super.foo();
    console.log(`from F -> inside instance of F: ${this instanceof F}`);
  }
}

// G class, C wrap to be used with new decorator, pretty format
class G extends C(Object) {}

const inst1 = new D(),
      inst2 = new E(),
      inst3 = new F(),
      inst4 = new G(),
      inst5 = new (B(Object)); // instance only B, ugly format

console.log(`Test D: extends A, B, C -> outside instance of D: ${inst1 instanceof D}`);
inst1.foo();
console.log('-');
console.log(`Test E: extends A, C -> outside instance of E: ${inst2 instanceof E}`);
inst2.foo();
console.log('-');
console.log(`Test F: extends B -> outside instance of F: ${inst3 instanceof F}`);
inst3.foo();
console.log('-');
console.log(`Test G: wraper to use C alone with "new" decorator, pretty format -> outside instance of G: ${inst4 instanceof G}`);
inst4.foo();
console.log('-');
console.log(`Test B alone, ugly format "new (B(Object))" -> outside instance of B: ${inst5 instanceof B}, this one fails`);
inst5.foo();

Will print out

Test D: extends A, B, C -> outside instance of D: true
from A -> inside instance of A: true
from B -> inside instance of B: true
from C -> inside instance of C: true
from D -> inside instance of D: true
-
Test E: extends A, C -> outside instance of E: true
from A -> inside instance of A: true
from C -> inside instance of C: true
from E -> inside instance of E: true
-
Test F: extends B -> outside instance of F: true
from B -> inside instance of B: true
from F -> inside instance of F: true
-
Test G: wraper to use C alone with "new" decorator, pretty format -> outside instance of G: true
from C -> inside instance of C: true
-
Test B alone, ugly format "new (B(Object))" -> outside instance of B: false, this one fails
from B -> inside instance of B: true

Link to fiddle around


in javascript you cant give to a class (constructor function) 2 different prototype object and because inheritance in javascript work with prototype soo you cant do use more than 1 inheritance for one class but you can aggregate and join property of Prototype object and that main property inside a class manually with refactoring that parent classes and next extends that new version and joined class to your target class have code for your question :

let Join = (...classList) => {

    class AggregatorClass {

        constructor() {
            classList.forEach((classItem, index) => {

                let propNames = Object.getOwnPropertyNames(classItem.prototype);

                propNames.forEach(name => {
                    if (name !== 'constructor') {
                        AggregatorClass.prototype[name] = classItem.prototype[name];
                    }
                });
            });

            classList.forEach(constructor => {
                Object.assign(AggregatorClass.prototype, new constructor())
            });
        }
    }


    return AggregatorClass

};


use Mixins for ES6 multiple Inheritence.

let classTwo = Base => class extends Base{
    // ClassTwo Code
};

class Example extends classTwo(ClassOne) {
    constructor() {
    }
}

Sergio Carneiro's and Jon's implementation requires you to define an initializer function for all but one class. Here is a modified version of the aggregation function, which makes use of default parameters in the constructors instead. Included are also some comments by me.

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;
}

Here is a little demo:

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.

This aggregation function will prefer properties and methods of a class that appear later in the class list.


Justin Fagnani describes a very clean (imho) way to compose multiple classes into one using the fact that in ES2015, classes can be created with class expressions.

Expressions vs declarations

Basically, just like you can create a function with an expression:

function myFunction() {}      // function declaration
var myFunction = function(){} // function expression

you can do the same with classes:

class MyClass {}             // class declaration
var MyClass = class {}       // class expression

The expression is evaluated at runtime, when the code executes, whereas a declaration is executed beforehand.

Using class expressions to create mixins

You can use this to create a function that dynamically creates a class only when the function is called:

function createClassExtending(superclass) {
  return class AwesomeClass extends superclass {
    // you class body here as usual
  }
}

The cool thing about it is that you can define the whole class beforehand and only decide on which class it should extend by the time you call the function:

class A {}
class B {}
var ExtendingA = createClassExtending(A)
var ExtendingB = createClassExtending(B)

If you want to mix multiple classes together, because ES6 classes only support single inheritance, you need to create a chain of classes that contains all the classes you want to mix together. So let's say you want to create a class C that extends both A and B, you could do this:

class A {}
class B extends A {}
class C extends B {}  // C extends both A and B

The problem with this is that it's very static. If you later decide you want to make a class D that extends B but not A, you have a problem.

But with some smart trickery using the fact that classes can be expressions, you can solve this by creating A and B not directly as classes, but as class factories (using arrow functions for brevity):

class Base {} // some base class to keep the arrow functions simple
var A = (superclass) => class A extends superclass
var B = (superclass) => class B extends superclass
var C = B(A(Base))
var D = B(Base)

Notice how we only decide at the last moment which classes to include in the hierarchy.


Answer

This is impossible. An object can only have one prototype in Javascript.

Workaround

You could use Object.assign which would work, but is unsafe and doesn't provide autocomplete or any type safety.

class Example {
  constructor (props) {
    Object.assign(this, new Class1(props))
    Object.assign(this, new Class2(props))
  }
}

Another way you should consider

In this example I'm assuming the goal of extending many is to be able to construct the Example class in one line, then have access to the methods in all the would-be-extended classes.

Optional: If the methods depend on methods in the super-class I suggest to create another BaseClass and have class Class1 extends BaseClass {}. This way the re-useable part of Example doesn't get rewritten.

class Class1 extends BaseClass {}
class Class2 extends BaseClass {}

class Example {
  class1: Class1 // Sorry for the Typescript
  class2: Class2

  constructor (props) {
    this.class1 = new Class1(props)
    this.class2 = new Class2(props)
  }
}

const example = new Example(props)
example.class1.someMethod()

I spent half a week trying to figure this out myself, and wrote a whole article on it, https://github.com/latitov/OOP_MI_Ct_oPlus_in_JS, and hope it helps some of you.

In short, here's how MI can be implemented in JavaScript:

    class Car {
        constructor(brand) {
            this.carname = brand;
        }
        show() {
            return 'I have a ' + this.carname;
        }
    }

    class Asset {
        constructor(price) {
            this.price = price;
        }
        show() {
            return 'its estimated price is ' + this.price;
        }
    }

    class Model_i1 {        // extends Car and Asset (just a comment for ourselves)
        //
        constructor(brand, price, usefulness) {
            specialize_with(this, new Car(brand));
            specialize_with(this, new Asset(price));
            this.usefulness = usefulness;
        }
        show() {
            return Car.prototype.show.call(this) + ", " + Asset.prototype.show.call(this) + ", Model_i1";
        }
    }

    mycar = new Model_i1("Ford Mustang", "$100K", 16);
    document.getElementById("demo").innerHTML = mycar.show();

And here's specialize_with() one-liner:

function specialize_with(o, S) { for (var prop in S) { o[prop] = S[prop]; } }

Again, please look at https://github.com/latitov/OOP_MI_Ct_oPlus_in_JS.


Here's an awesome/really crappy way of extending multiple classes. I'm utilizing a couple functions that Babel put into my transpiled code. The function creates a new class that inherits class1, and class1 inherits class2, and so on. It has its issues, but a fun idea.

var _typeof = typeof Symbol === 'function' && typeof Symbol.iterator === 'symbol' ? function (obj) {
  return typeof obj
} : function (obj) {
  return obj && typeof Symbol === 'function' && obj.constructor === Symbol ? 'symbol' : typeof obj
}

function _inherits (subClass, superClass) {
  if (typeof superClass !== 'function' && superClass !== null) {
    throw new TypeError('Super expression must either be null or a function, not ' + (
      typeof superClass === 'undefined' ? 'undefined' : _typeof(superClass)))
  }
  subClass.prototype = Object.create(
    superClass && superClass.prototype,
    {
      constructor: {
        value: subClass,
        enumerable: false,
        writable: true,
        configurable: true
      }
    })
  if (superClass) {
    Object.setPrototypeOf
    ? Object.setPrototypeOf(subClass, superClass)
    : subClass.__proto__ = superClass.__proto__  // eslint-disable-line no-proto
  }
}

function _m (...classes) {
  let NewSuperClass = function () {}
  let c1 = NewSuperClass
  for (let c of classes) {
    _inherits(c1, c)
    c1 = c
  }
  return NewSuperClass
}

import React from 'react'

/**
 * Adds `this.log()` to your component.
 * Log message will be prefixed with the name of the component and the time of the message.
 */
export default class LoggingComponent extends React.Component {
  log (...msgs) {
    if (__DEBUG__) {
      console.log(`[${(new Date()).toLocaleTimeString()}] [${this.constructor.name}]`, ...msgs)
    }
  }
}

export class MyBaseComponent extends _m(LoggingComponent, StupidComponent) {}

I have been using a pattern like this to program complex multi inheritance things:

var mammal = {
    lungCapacity: 200,
    breath() {return 'Breathing with ' + this.lungCapacity + ' capacity.'}
}

var dog = {
    catchTime: 2,
    bark() {return 'woof'},
    playCatch() {return 'Catched the ball in ' + this.catchTime + ' seconds!'}
}

var robot = {
    beep() {return 'Boop'}
}


var robotDogProto = Object.assign({}, robot, dog, {catchTime: 0.1})
var robotDog = Object.create(robotDogProto)


var livingDogProto = Object.assign({}, mammal, dog)
var livingDog = Object.create(livingDogProto)

This method uses very little code, and allows for things like overwriting default properties (like I do with a custom catchTime in robotDogProto)


This isn't really possible with the way prototypical inheritance works. Lets take a look at how inherited props work in js

var parent = {a: function() { console.log('ay'); }};
var child = Object.create(parent);
child.a() // first look in child instance, nope let's go to it's prototype
          // then look in parent, found! return the method

let's see what happens when you access a prop that doesn't exist:

child.b; // first look in child instance, nope let's go to it's prototype
         // then look in parent, nope let's go to it's prototype
         // then look in Object.prototype, nope let's go to it's prototype
         // then look at null, give up and return undefined

You can use mixins to get some of that functionality but you won't get late binding:

var a = {x: '1'};
var b = {y: '2'};
var c = createWithMixin([a, b]);
c.x; // 1
c.y; // 2
b.z = 3;
c.z; // undefined

vs

var a = {x: 1}
var o = Object.create(a);
o.x; // 1
a.y = 2;
o.y; // 2

This ES6 solution worked for me:

multiple-inheritance.js

export function allOf(BaseClass, ...Mixins) {

  function copyProperties(target, source) {
    const allPropertyNames = Object.getOwnPropertyNames(source).concat(Object.getOwnPropertySymbols(source))

    allPropertyNames.forEach((propertyName) => {
      if (propertyName.match(/^(?:constructor|prototype|arguments|caller|name|bind|call|apply|toString|length)$/))
        return
      Object.defineProperty(target, propertyName, Object.getOwnPropertyDescriptor(source, propertyName))
    })
  }

  class Base extends BaseClass
  {
    constructor (...args) {
      super(...args)

      Mixins.forEach((Mixin) => {
        copyProperties(this, new Mixin(...args))
      })
    }
  }

  Mixins.forEach((mixin) => {
    copyProperties(Base.prototype, Mixin.prototype)
  })

  return Base
}

main.js

import { allOf } from "./multiple-inheritance.js"

class A
{
    constructor(name) {
        this.name = name
    }
    sayA() {
        return this.name
    }
}

class B
{
    constructor(name) {
        this.name = name
    }
    sayB() {
        return this.name
    }
}

class AB extends allOf(A, B)
{
    sayAB() {
        return this.name
    }
}

const ab = new AB("ab")
console.log("ab.sayA() = "+ab.sayA()+", ab.sayB() = "+ab.sayB()+", ab.sayAB() = "+ab.sayAB())

Yields on browser-console:

ab.sayA() = ab, ab.sayB() = ab, ab.sayAB() = ab

From the page es6-features.org/#ClassInheritanceFromExpressions, it is possible to write an aggregation function to allow multiple inheritance:

class Rectangle extends aggregation(Shape, Colored, ZCoord) {}

var aggregation = (baseClass, ...mixins) => {
    let base = class _Combined extends baseClass {
        constructor (...args) {
            super(...args)
            mixins.forEach((mixin) => {
                mixin.prototype.initializer.call(this)
            })
        }
    }
    let copyProps = (target, source) => {
        Object.getOwnPropertyNames(source)
            .concat(Object.getOwnPropertySymbols(source))
            .forEach((prop) => {
            if (prop.match(/^(?:constructor|prototype|arguments|caller|name|bind|call|apply|toString|length)$/))
                return
            Object.defineProperty(target, prop, Object.getOwnPropertyDescriptor(source, prop))
        })
    }
    mixins.forEach((mixin) => {
        copyProps(base.prototype, mixin.prototype)
        copyProps(base, mixin)
    })
    return base
}

But that is already provided in libraries like aggregation.