创建多个抽象类javascript ES6

时间:2017-07-26 20:08:22

标签: javascript oop ecmascript-6 abstract-class

今天我想出了一个使用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));

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

1 个答案:

答案 0 :(得分:3)

缺点是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 {...}

AbstractAbstractFoo会在直接实例化时抛出错误。

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

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

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

class ConcreteFoo extends AbstractFoo {...}

请注意,对于装饰器,在抛出错误之前将对原始构造函数进行求值,这是使用extends的代价。解决方法是使用函数而不是类,并手动从target继承它,类似于TypeScript __extendsBabel __inherits辅助函数,这样就可以在super()之前抛出错误。另一种解决方法是使用new.target(目前无法通过Babel转换为ES5):

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

更简洁的方法是使用TypeScript(在评论中建议),它将抽象类作为语言功能引入,并在设计时处理它。这样就不会污染原型链。