调用方法由没有 super 的 mixin 实现

Calling methods implemend by mixins without super

我想要一个 mixin class,它期望具体的 class 定义特定的方法。类似于:

function BaseMixin(Base) {
  class Mixin extends Base {
    doSomething() {
      this.onSomethingDone()
    }
  }

  return Mixin
}

同时,我允许可选的 mixins 也可能声明这样的方法。最终结果是具体 class 和每个 mixin 都需要调用 super.onSomethingDone 并且因为应用 mixin 的顺序可以改变,所以它们还必须检查方法是否存在:

function SecondaryMixin(Base) {
  class Mixin extends Base {
    onSomethingDone() {
      if (super.onSomethingDone)
        super.onSomethingDone()

      // stuff specific to SecondaryMixin
    }
  }

  return Mixin
}

class ConcreteClass extends SecondaryMixin(BaseMixin(HTMLElement)) {
  doSomething() {
    if (super.onSomethingDone)
      super.onSomethingDone()

    // stuff specific to ConcreteClass
  }
}

这很乏味且容易出错。相反,是否有可能只让实现者执行他们的 specific stuff 并在 BaseMixin 中以某种方式迭代并从所有应用的混合中调用 onSomethingDone 的所有实现?

function BaseMixin(Base) {
  class Mixin extends Base {
    doSomething() {
      for (let onSomethingDone of getAllImplementationsThereof()) {
        onSomethingDone()
      }
    }
  }
}

您可以这样实施 getAllImplementations

function getAllImplementationsOf(cls, methodName) {
    let fns = [];

    cls = Object.getPrototypeOf(cls);

    while (cls) {
        if (cls.prototype && cls.prototype.hasOwnProperty(methodName))
            fns.push(cls.prototype[methodName]);
        cls = Object.getPrototypeOf(cls);
    }

    return fns;
}

//


function FirstMixin(Base) {
    return class Mixin extends Base {
        work() {
            console.log('first')
        }
    }
}

function SecondMixin(Base) {
    return class Mixin extends Base {
        work() {
            console.log('second')
        }
    }
}

class Base {
}

class ConcreteClass extends FirstMixin(SecondMixin(Base)) {

    work() {
        for (let fn of getAllImplementationsOf(this.constructor, 'work'))
            fn.call(this);
        console.log('done!')
    }
}

new ConcreteClass().work();

话虽这么说,我不确定 extends 是否是实现混入的正确工具,正是因为这类问题。我宁愿研究代理。