继承自JS中的两个(或多个)内置对象(Map,EventTarget)

时间:2019-03-30 11:39:00

标签: javascript class inheritance

我不是JS的Noob,而且我知道从技术上讲,没有正确的方法可以从多个类继承。所以我的问题很简单

有什么主意,我该如何创建一个类或只是一个从JS Native对象的两个内部版本继承而来的对象。特别是EventTarget和另一个对象。

我尝试:

var map = new Map();
var eventtarget = new EventTarget();
mix = Object.create({...Map.prototype, ...EventTarget.prototype});
Object.assign(mix, et , map);

似乎不起作用,因为Map.prototype中的方法不是可迭代的 也使用Object.assign({}, Map.prototype, ...EventTarget.prototype)具有相同的效果。

另一种尝试:

class Base5 extends Map{
 constructor(){
    super();
    var eventTarget = new EventTarget();
    Object.assign(this,eventTarget);
 }
}

Base5.prototype = Object.create(Base5.prototype)
Object.assign(Base5.prototype,EventTarget.prototype); 

//    that seem to work
const b5 = new Base5();
b5.set('foo','bar');
//    but... 
b4.addEventListener('fire', _=>_ )
// throw Uncaught TypeError: Illegal invocation at <anonymous>:1:4

此方法有效,但不通用

const wm = new WeakMap();

class Base6 extends Map{
 constructor(){
    super();
    wm.set(this, new EventTarget() )
 }
 addEventListener(){ 
    wm.get(this).addEventListener(...arguments)
 }
 dispatchEvent(){
    wm.get(this).dispatchEvent(...arguments)
 }
 removeEventListener(){
   wm.get(this).removeEventListener(...arguments)
 }
}

const b6 = new Base6();
b6.set('foo','bar'); // Map(1) {"foo" => "bar"}
b6.addEventListener('foo', e=>console.log(e) );
b6.dispatchEvent( new Event('foo') ) 

那么任何人都可以采用更好的方法?

也许Reflect.construct可以在某种程度上为您提供帮助

3 个答案:

答案 0 :(得分:1)

您可以创建一个函数,该函数创建基类的私有实例,并返回一个代理,该代理将属性检索分配给那些对象之一。可以将基类传递给构造函数以使其保持通用:

createMix(Map, EventTarget)

几件事仍然是有问题的。一个阻塞问题是方法调用通常需要将this设置为基础对象才能起作用。解决方法可能是返回一个绑定的方法,知道它本身可能会产生不良影响(例如,客户根本无法采用该方法并将其自身绑定到其他对象上-如果这完全有意义)。

可以肯定的是,这并不能解决所有潜在的问题,但似乎可以在非常基本的用法中起作用:

function createMix(...classes) {
    const obj = {};
    const instances = [obj, ...classes.map(cls => new cls)];
    return new Proxy(obj, {
        get(obj, prop) {
            obj = instances.find(obj => prop in obj);
            const val = Object(obj)[prop];
            return typeof val === "function" ? val.bind(obj) : val;
        },
        has(obj, prop) { // Optional: if you care about the `in` operator
            return instances.some(obj => prop in obj);
        }
    });
}

// Tiny test
const obj = createMix(Map, EventTarget);
obj.set('foo','bar'); 
console.log("Map contains: ", Object.fromEntries(obj));
obj.addEventListener('foo', e => console.log("Event object type: ", e.type) );
obj.dispatchEvent( new Event('foo') );

此函数返回一个容器对象,因此不会instanceof传递给该函数的任何基类。

答案 1 :(得分:1)

@trincot show-me-a-way / inspire-me进行了更多研究,并提供了可改善其解决方案某些方面的以下解决方案:

1)对继承函数的弱绑定
2)能够使用混合类作为原型来扩展另一个自定义类。

如果您喜欢我的答案,也不要忘记竖起大拇指。

最后,简码可以扩展多个本机类,可能并不完美,因此,如果发现问题,请发表评论,但这只是一个开始,我们将来可以改进它:

MainAxisAlignment.spaceEvenly

答案 2 :(得分:0)

目前,对于寻求解决该问题的其他人,我将采用这种解决方案

const wm = new WeakMap();

function Emitter(Base) {
   return class extends Base {
    constructor() {
        super(...arguments);
        wm.set(this, new EventTarget())
    }

    addEventListener() {
        wm.get(this).addEventListener(...arguments)
    }

    dispatchEvent() {
        wm.get(this).dispatchEvent(...arguments)
    }

    removeEventListener() {
        wm.get(this).removeEventListener(...arguments)
    }
  }
}

// how to use
const EmitterableMap = Emitter(Map);