ES6类多重继承

时间:2015-04-26 15:03:29

标签: javascript ecmascript-6

我已经在BabelJSMDN(根本没有任何信息)上完成了我的大部分研究,但请随时告诉我,如果我不够谨慎四处寻找有关ES6 Spec。

的更多信息

我想知道ES6是否支持多种继承,就像其他鸭式语言一样。例如,我可以这样做:

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

将多个类扩展到新类?如果是这样,解释器是否会更喜欢ClassTwo上的方法/属性而不是ClassOne?

22 个答案:

答案 0 :(得分:63)

检查我的示例,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

Link to fiddle around

答案 1 :(得分:55)

一个对象只能有一个原型。可以通过将父对象创建为两个父原型的组合来继承两个类。

子类化的语法使得在声明中可以这样做,因为extends子句的右侧可以是任何表达式。因此,您可以编写一个根据您喜欢的标准组合原型的函数,并在类声明中调用该函数。

答案 2 :(得分:18)

Sergio Carneiro's and Jon's implementation要求您为除一个类之外的所有类定义初始化函数。以下是聚合函数的修改版本,它使用构造函数中的默认参数。还包括我的一些评论。

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.

此聚合函数更喜欢稍后出现在类列表中的类的属性和方法。

答案 3 :(得分:9)

Justin Fagnani describes一种非常干净(imho)的方法,使用在ES2015中可以使用类表达式创建类的事实将多个类组合成一个。

表达式与声明

基本上,就像你可以用表达式创建一个函数:

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

你可以对课程做同样的事情:

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

表达式在运行时在代码执行时进行计算,而声明则在事先执行。

使用类表达式创建mixins

您可以使用它来创建一个仅在调用函数时动态创建类的函数:

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类仅支持单继承,您需要创建一个包含要混合在一起的所有类的类链。所以,让我们说你要创建一个扩展A和B的C类,你可以这样做:

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

这个问题是它非常静态。如果你以后决定要制作一个扩展B而不是A的D类,那你就有问题了。

但是使用类可以是表达式这一事实的一些聪明的诡计,你可以通过不直接创建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

  

mics (发音:mix)是一个在Javascript中进行多重继承的库。受到Justin Fagnani的优秀博客文章“Real”Mixins和Javascript Classes的启发,麦克风试图围绕使用类表达式(工厂)作为mixins的概念构建一个最小的库。 mics扩展了博客文章中提出的概念,通过使mixin成为一流的公民,可以直接用于实例化对象,并且可以与其他mixin混合使用,而不仅仅是与类混合。

答案 4 :(得分:8)

原型继承的工作原理并非如此。让我们看看继承的道具如何在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

让我们看看当你访问一个不存在的道具时会发生什么:

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

您可以使用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

VS

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

答案 5 :(得分:5)

我的答案似乎更少的代码,并且对我有用:

    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!

答案 6 :(得分:2)

从页面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这样的库中提供了它。

答案 7 :(得分:2)

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

具有最佳的TS支持和许多其他有用的功能!

答案 8 :(得分:2)

我想出了这些解决方案:

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

在节点v5.4.1中使用--harmony flag

为我工作

答案 9 :(得分:1)

使用Mixins for ES6 multiple Inheritence。

private int getItemPosition(Item item){ // (<-- replace with your item)
    int i = 0;
    // (replace with your items and methods here)
    for (Item currentItem : mItems) {
        if (currentItem.getItemId() == item.getItemId()) break;
        i++;
    }
    return i;
}

答案 10 :(得分:1)

在javascript中,您不能给一个类(构造函数)2个不同的原型对象,并且由于javascript中的继承与原型一起工作,因此您不能对一个类使用超过1个继承,但是并手动将Prototype对象的join属性和该类中的main属性重构,以重构父类,然后将新版本和加入的类扩展到您的 target 类中,其中包含针对您问题的代码

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

};

答案 11 :(得分:1)

我花了半周的时间自己弄清楚这个问题,并在上​​面写了整篇文章https://github.com/latitov/OOP_MI_Ct_oPlus_in_JS,希望对您有所帮助。

简而言之,这是可以在JavaScript中实现MI的方法:

    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

答案 12 :(得分:1)

我还将添加解决方案-从此线程中阅读的内容中,我发现它对我自己最友好。

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 :(得分:1)

这个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

答案 14 :(得分:1)

没有简单的方法来进行多类继承。我遵循关联和继承的组合来实现这种行为。

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

希望这有用。

答案 15 :(得分:1)

Object.assign让你有可能做一些近似的事情,虽然有点像ES6课程的作文。

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

我没有看到这在任何地方使用,但实际上非常有用。您可以使用function shark(){}而不是类,但使用类更有优势。

我认为唯一与extend关键字的继承不同的是,该功能不仅仅存在于prototype上,而且还存在于对象本身。

因此,当您执行new Shark()时,shark创建的bite方法具有eat方法,而只有其原型具有unique()方法

答案 16 :(得分:0)

作为概念证明,我完成了以下功能。它获取一个类列表,并将它们组成一个新类(最后一个原型获胜,因此没有冲突)。创建组合函数时,用户可以选择使用所有原始构造函数[ sic!]或传递自己的构造函数。这是该实验的最大挑战:提出构造函数应该做什么的描述。将方法复制到原型中不是问题,但是新组成对象的预期逻辑是什么。还是应该没有构造函数?据我所知,在Python中,它找到了 matching 构造函数,但是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);

最初发布的here(gist.github.com)。

答案 17 :(得分:0)

使用自定义函数的extent来处理与es6的多重继承

&#13;
&#13;
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)
&#13;
&#13;
&#13;

答案 18 :(得分:0)

我一直在使用这样的模式来编程复杂的多继承事物:

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)

此方法使用的代码很少,并且可以进行诸如覆盖默认属性的操作(例如我对robotDogProto中的自定义catchTime所做的操作)

答案 19 :(得分:0)

下面的解决方案(通过复制实例字段和原型属性进行类克隆)对我有用。我使用的是普通 JS(即不是 Typescript),带有 JsDoc 注释和用于编译时类型检查的 VSCode。

解决方案界面非常简单:

$("#buttonHide")

所涉及的类可以像普通的 ES6 类一样创建。

但是需要做到以下几点:

  • 使用 isInstanceOf() 而不是内置运算符 instanceof。
  • 不要使用“super”来调用基类的非构造函数成员,而是使用函数 super2()。
  • 不要在构造函数中编写任何代码,而是将其编写在名为“init()”的类方法中,该方法又由构造函数调用。请参阅下面的示例。
class DerivedBase extends cloneClass(Derived, Base) {}

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

let o = new DerivedBase()  

注意事项:JSDoc 交集运算符 & 可能并不总是有效。在这种情况下,可能需要使用其他一些解决方案。例如,可能需要定义一个单独的接口类来“手动”组合这两个类。这个接口类可以从一个类扩展,另一个类的接口可以使用 VsCode 快速修复选项自动实现。

答案 20 :(得分:0)

答案

这是不可能的。一个对象在 JavaScript 中只能有一个 prototype

解决方法

您可以使用 Object.assign ,它可以工作,但不安全并且不提供自动完成或任何类型安全。

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

你应该考虑的另一种方式

在此示例中,我假设扩展多个类的目标是能够在一行中构造 Example 类,然后可以访问所有可能要扩展的类中的方法。

>

可选:如果方法依赖于超类中的方法,我建议创建另一个 BaseClass 并拥有 class Class1 extends BaseClass {}。这样,Example 的可重用部分就不会被重写。

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

答案 21 :(得分:-3)

这是扩展多个类的一种非常棒/非常糟糕的方式。我正在使用Babel为我编译的代码添加的几个函数。该函数创建一个继承class1的新类,class1继承class2,依此类推。它有它的问题,但是一个有趣的想法。

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