创建多个抽象类 javascript ES6

Ber*_*gan 2 javascript oop abstract-class ecmascript-6

今天我想出了一个想法,使用Proxy对象,允许创建多个抽象类,例如

const abstract = abstractClass => new Proxy(abstractClass,{
  construct: (target, args) => { throw new Error('Error, class was declared as abstract!') }
});

class A{}
class B{}
class C{}
[A,B,C] = [A,B,C].map(c => abstract(c));
Run Code Online (Sandbox Code Playgroud)

所以我的问题是这个解决方案是否有任何缺点,如果有,它们是什么。

Est*_*ask 5

缺点是Proxy在 ES5 中无法可靠地进行聚合填充,而且速度很慢。

一个好的方法是通过继承来解决这个问题:

class Abstract {
    constructor() {
        if (Object.getPrototypeOf(this.constructor) === Abstract
            || this.constructor === Abstract) {
            throw new Error("Cannot instantiate abstract class");
        }
    }
};

class AbstractFoo extends Abstract {...}

class ConcreteFoo extends AbstractFoo {...}
Run Code Online (Sandbox Code Playgroud)

Abstract直接实例化时会AbstractFoo抛出错误。

ES.next 装饰器可以使任务变得更容易:

function abstract(target) {
    return class Abstract extends target {
        constructor(...args) {
            super(...args);
            if (this.constructor === Abstract) {
                throw new Error("Cannot instantiate abstract class");
            }
        }
    };
}
@abstract
class AbstractFoo {...}

class ConcreteFoo extends AbstractFoo {...}
Run Code Online (Sandbox Code Playgroud)

由于装饰器基本上是辅助函数,因此可以直接在普通 ES6 中应用它们:

const AbstractFoo = abstract(class AbstractFoo {...});

class ConcreteFoo extends AbstractFoo {...}
Run Code Online (Sandbox Code Playgroud)

请注意,在装饰器的情况下,将在抛出错误之前评估原始构造函数,这是使用extends. 解决方法是使用函数而不是类并target手动继承它,类似于TypeScript__extends

  • Babel 支持还不太完善,但你也可以使用 new.target === Abstract 来代替检查,它可以在 super(...) 之前使用 (2认同)