首页 > 解决方案 > 从 JS 中的两个(或更多)内置对象(Map、EventTarget)继承

问题描述

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

有什么想法可以创建一个类或只是一个对象,它继承自 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可以以某种方式在这里提供帮助

标签: javascriptclassinheritance

解决方案


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

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传递给该函数的任何基类。


推荐阅读