ES6 Класс Множественное наследование

Я провел большую часть своих исследований по этому вопросу на BabelJS и на MDN (который не имеет никакой информации), но, пожалуйста, не стесняйтесь сказать мне, если я не был достаточно осторожен в поисках дополнительной информации о спецификации ES6.

Мне интересно, поддерживает ли ES6 множественное наследование так же, как и другие языки с утиным языком. Например, могу ли я сделать что-то вроде:

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

чтобы расширить несколько классов на новый класс? Если да, то интерпретатор предпочитает методы/свойства ClassTwo над ClassOne?

Ответ 1

Объект может иметь только один прототип. Наследование из двух классов может быть выполнено путем создания родительского объекта в виде комбинации двух родительских прототипов.

Синтаксис для подклассификации позволяет сделать это в объявлении, поскольку правая часть предложения extends может быть любым выражением. Таким образом, вы можете написать функцию, которая объединяет прототипы в соответствии с любыми критериями, которые вы хотите, и вызывать эту функцию в объявлении класса.

Ответ 2

Посмотрите мой пример ниже, super метод работает, как и ожидалось. Используя несколько трюков, даже instanceof работает (большую часть времени):

// 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();

Распечатает

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

Ссылка, чтобы возиться

Ответ 3

Для реализации Sergio Carneiro и Jon требуется определить функцию инициализатора для всех классов, кроме одного. Вот модифицированная версия функции агрегирования, которая вместо этого использует параметры по умолчанию в конструкторах. Включены также некоторые комментарии от меня.

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.

Эта функция агрегирования предпочтет свойства и методы класса, которые появятся позже в списке классов.

Ответ 4

Джастин Фагнани описывает очень чистый (imho) способ объединения нескольких классов в один, используя тот факт, что в ES2015 классы можно создавать с помощью выражений классов.

Выражения против объявлений

По сути, так же, как вы можете создать функцию с выражением:

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

вы можете сделать то же самое с классами:

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

Выражение вычисляется во время выполнения, когда код выполняется, тогда как объявление выполняется заранее.

Использование выражений классов для создания миксинов

Вы можете использовать это для создания функции, которая динамически создает класс только при вызове функции:

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

Крутая вещь в этом заключается в том, что вы можете определить весь класс заранее и решить, какой класс он должен расширить, к моменту вызова функции:

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

Если вы хотите смешать несколько классов вместе, потому что классы ES6 поддерживают только одно наследование, вам нужно создать цепочку классов, которая содержит все классы, которые вы хотите смешать вместе. Допустим, вы хотите создать класс C, который расширяет как A, так и B, вы можете сделать это:

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

Проблема в том, что это очень статично. Если позже вы решите, что хотите создать класс D, который расширяет B, но не A, у вас есть проблема.

Но с помощью некоторых хитрых хитростей, использующих тот факт, что классы могут быть выражениями, вы можете решить эту проблему, создавая A и B не непосредственно как классы, а как фабрики классов (для краткости используя функции стрелок):

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)

Обратите внимание, как мы в последний момент решаем, какие классы включить в иерархию.

Помогите нам построить будущее!

Конечно, если вы похожи на меня, это вдохновит вас на создание окончательной библиотеки множественного наследования в Javascript. Если вы готовы, пожалуйста, помогите мне сделать именно это! Проверьте этот проект и помогите, если сможете!

микрофоны

mics (произношение: mix) - это библиотека, которая делает множественное наследование в Javascript быстрым. Вдохновленный отличным сообщением в блоге "Настоящие" миксины с классами Javascript Джастином Фагнани, микрофоны пытаются создать минимальную библиотеку вокруг концепции использования выражений классов (фабрик) в качестве миксинов. mics расширяет концепции, представленные в сообщении блога, делая миксины первоклассными гражданами, которые можно напрямую использовать для создания объектов и смешивать их с другими миксинами, а не только с классами.

Ответ 5

Это не совсем возможно с тем, как работает прототипное наследование. Давайте посмотрим, как унаследованные реквизиты работают в js

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

посмотрим, что произойдет, когда вы получите доступ к опоре, которая не существует:

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

Вы можете использовать mixins, чтобы получить некоторые из этих функций, но вы не получите позднюю привязку:

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

против

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

Ответ 6

Я придумал это решение:

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

использование:

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

Пока вы делаете эти трюки с помощью своих привычных классов, он может быть прикован. но мы скоро, так как вы хотите расширить некоторую функцию/класс, написанную не так, - у вас не будет шанса продолжить цикл.

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

работает для меня в node v5.4.1 с флагом -harmony

Ответ 7

На странице es6-features.org/#ClassInheritanceFromExpressions можно написать функцию агрегации, чтобы разрешить множественное наследование:

Класс Rectangle расширяет агрегацию (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
}

Но это уже имеется в библиотеках, таких как aggregation.

Ответ 8

используйте Mixins для ES6 multiple Inheritence.

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

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

Ответ 9

Ну Object.assign дает вам возможность сделать что-то близкое, хотя и немного похожее на композицию с ES6-классами.

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

class Shark {
  // only what 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();

Я не видел, чтобы это использовалось где угодно, но это действительно полезно. Вы можете использовать function shark(){} вместо класса, но есть преимущества использования класса.

Я считаю, что единственное отличие с наследованием с ключевым словом extend заключается в том, что функция не живет только на prototype, но также и на самом объекте.

Таким образом, теперь, когда вы делаете new Shark(), созданный shark имеет метод bite, тогда как только его прототип имеет метод eat

Ответ 10

Нет простого способа выполнить множественное наследование класса. Я следую сочетанию ассоциации и наследования для достижения такого поведения.

    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());

Надеюсь, что это будет полезно.

Ответ 11

Это решение ES6 сработало для меня:

многооконном 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())

Выходы на браузер-консоли:

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

Ответ 12

Я также добавлю свое решение - я нашел его наиболее дружественным для себя из того, что я прочитал в этой теме.

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

Вы можете использовать его тогда так:

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

Ответ 13

использовать степень с пользовательской функцией для обработки множественного наследования с помощью es6

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
}

class Colored {
    initializer ()     { this._color = "white" }
    get color ()       { return this._color }
    set color (v)      { this._color = v }
}

class ZCoord {
    initializer ()     { this._z = 0 }
    get z ()           { return this._z }
    set z (v)          { this._z = v }
}

class Shape {
    constructor (x, y) { this._x = x; this._y = y }
    get x ()           { return this._x }
    set x (v)          { this._x = v }
    get y ()           { return this._y }
    set y (v)          { this._y = v }
}

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

var rect = new Rectangle(7, 42)
rect.z     = 1000
rect.color = "red"
console.log(rect.x, rect.y, rect.z, rect.color)

Ответ 14

это работает для меня! (2019)

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

Ответ 15

В качестве доказательства концепции я выполнил следующую функцию. Он берет список классов и объединяет их в новый класс (последний прототип выигрывает, поэтому нет конфликтов). При создании составной функции пользователь может выбрать использование всех оригинальных конструкторов [sic!] Или передать свои собственные. Это было самой большой проблемой этого эксперимента: придумать описание того, что должен делать конструктор. Копирование методов в прототип - это не проблема, а то, что подразумевается под логикой вновь составленного объекта. Или, может быть, это должно быть без конструктора? В Python, насколько я знаю, он находит соответствующий конструктор, но функции в JS более приемлемы, поэтому можно перейти к функции практически во всем, и из сигнатуры это не будет понятно.

Я не думаю, что это оптимизировано, но целью было изучение возможностей. instanceof будет вести себя не так, как ожидается, что, как мне кажется, является обломом, поскольку разработчики, ориентированные на классы, любят использовать это как инструмент.

Может быть, JavaScript просто не имеет его.

/*
    (c) Jon Krazov 2019

    Below is an experiment searching boundaries of JavaScript.
    It allows to compute one class out of many classes.

    Usage 1: Without own constructor

    If no constructor is passed then constructor of each class will be called
    with params passed in object. In case of missing params, constructor
    will be called without params.

    Example:

    const MyClass1 = computeClass([Class1, Class2, Class3]);
    const myClass1Instance = new MyClass1({
        'Class1': [1, 2],
        'Class2': ['test'],
        'Class3': [(value) => value],
    });

    Usage 2: With own constructor

    If constructor is passed in options object (second param) then it will
    be called in place of constructors of all classes.

    Example:

    const MyClass2 = computeClass([Class1, Class2, Class3], {
        ownConstructor(param1) {
            this.name = param1;
        }
    });
    const myClass2Instance = new MyClass2('Geoffrey');
*/

// actual function

var computeClass = (classes = [], { ownConstructor = null } = {}) => {
    const noConstructor = (value) => value != 'constructor';

    const ComputedClass = ownConstructor === null
        ? class ComputedClass {
            constructor(args) {
                classes.forEach((Current) => {
                    const params = args[Current.name];

                    if (params) {
                        Object.assign(this, new Current(...params));
                    } else {
                        Object.assign(this, new Current());
                    }
                })
            }
        }
        : class ComputedClass {
            constructor(...args) {
                if (typeof ownConstructor != 'function') {
                    throw Error('ownConstructor has to be a function!');
                }
                ownConstructor.call(this, ...args);
            } 
        };

    const prototype = classes.reduce(
        (composedPrototype, currentClass) => {
            const partialPrototype = Object.getOwnPropertyNames(currentClass.prototype)
                .reduce(
                    (result, propName) =>
                        noConstructor(propName)
                            ? Object.assign(
                                    result,
                                    { [propName]: currentClass.prototype[propName] }
                                )
                            : result,
                    {}
                );

            return Object.assign(composedPrototype, partialPrototype);
        },
        {}
    );

    Object.entries(prototype).forEach(([prop, value]) => {
	Object.defineProperty(ComputedClass.prototype, prop, { value });
    });
    
    return ComputedClass;
}

// demo part

var A = class A {
    constructor(a) {
        this.a = a;
    }
    sayA() { console.log('I am saying A'); }
}

var B = class B {
    constructor(b) {
        this.b = b;
    }
    sayB() { console.log('I am saying B'); }
}

console.log('class A', A);
console.log('class B', B);

var C = computeClass([A, B]);

console.log('Composed class');
console.log('var C = computeClass([A, B]);', C);
console.log('C.prototype', C.prototype);

var c = new C({ A: [2], B: [32] });

console.log('var c = new C({ A: [2], B: [32] })', c);
console.log('c instanceof A', c instanceof A);
console.log('c instanceof B', c instanceof B);

console.log('Now c will say:')
c.sayA();
c.sayB();

console.log('---');

var D = computeClass([A, B], {
    ownConstructor(c) {
        this.c = c;
    }
});

console.log('var D = computeClass([A, B], {
    ownConstructor(c) {
        this.c = c;
    }
});');

var d = new D(42);

console.log('var d = new D(42)', d);

console.log('Now d will say:')
d.sayA();
d.sayB();

console.log('---');

var E = computeClass();

console.log('var E = computeClass();', E);

var e = new E();

console.log('var e = new E()', e);

Ответ 16

Я потратил пол недели, пытаясь выяснить это сам, и написал целую статью об этом, https://github.com/latitov/OOP_MI_Ct_oPlus_in_JS, и надеюсь, что это поможет некоторым из вас.

Вкратце, вот как MI может быть реализовано в 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();

А здесь specialize_with() с одной строкой:

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

Снова, пожалуйста, посмотрите на https://github.com/latitov/OOP_MI_Ct_oPlus_in_JS.

Ответ 17

Здесь потрясающий/действительно дрянной способ расширения нескольких классов. Я использую пару функций, которые Бабель вложил в мой перекодированный код. Функция создает новый класс, который наследует class1, а class1 наследует класс2 и т.д. У этого есть свои проблемы, но забавная идея.

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) {}