在不使用超级构造函数的情况下,如何让 ES6 Class 方法在调用子类函数时执行一些默认行为?

How could I make a ES6 Class method execute some some default behaviour when a subclass function is called, without using the super constructor?

所以尝试构建一些 js classes 我 运行 遇到了一些知识空白,因为这是我第一次实现 OOP 和 ES6 构造函数。

我基本上有一个 运行 是一个 respond() 方法的应用程序,当在 "Emergency Event" 执行时,我需要从其父 class 执行一些默认行为].

在这个例子中,所有从 NuclearStrategy 派生的子class 应该总是 Appease the population 无论在 Action 子class respondToThreat() 方法为例。如果 eventIsJustTest === true 那么除了 Appease the population.

什么都不应该做

这就是我正在实施的:

class NuclearStrategy {
  constructor(props) {
    this.eventOrigin = props.eventOrigin;
  }

  appeaseAllPopulation() {
    console.log('✅ Appeasing the population');
  }

  respondToThreat({ eventIsJustTest }) {
    this.appeaseAllPopulation();
    if (eventIsJustTest) return;                            // I expect this to exit the function and ignore anything declared after <super.respondToThreat()>
  }
}


class Action extends NuclearStrategy {
  constructor(props) {
    super(props)
  }

  respondToThreat(responseArgs) {
    super.respondToThreat(responseArgs.eventIsJustTest);   // <- I can't have this in my code
    console.log(`✅ Playing alert siren`);                 // <- This shouldn't be executed
    console.log(`✅ Launched ICBM nuke to enemy`)          // <- Avoid also
  }
}


new Action({ eventOrigin: 'East Qorea' }).respondToThreat({ eventIsJustTest: true });

这执行

✅ Appeasing the population
✅ Playing alert siren
✅ Launched ICBM nuke to enemy

应该只执行

✅ Appeasing the population

有了这个,即使警报只是针对 nuclear test(RIP Earth),我也无法阻止使用 Action.respondToThreat 发射的核弹。另外,我的子 class super.respondToThreat() 不能有任何 super 调用,默认情况下应该执行 appeaseAllPopulation() 行为 没有调用它.

您对这个申请有什么建议吗? 提前谢谢你。

一个简单的解决方案是根本不覆盖 respondToThreat,而是调用应由子 类.

实现的 method/hook

class NuclearStrategy {
  constructor(props) {
    this.eventOrigin = props.eventOrigin;
  }

  appeaseAllPopulation() {
    console.log('Broadcasting ');
  }

  respondToThreat({ eventIsJustTest }) {
    console.log(`✅ Appeasing the population`);
    if (eventIsJustTest) return;
    this.respondToNonTestThreat();
  }
  
  respondToNonTestThreat() {} // default implementation do nothing
}

class Action extends NuclearStrategy {
  respondToNonTestThreat() {
    console.log(`✅ Playing alert siren`);
    console.log(`✅ Launched ICBM nuke to enemy`);
  }
}

const action = new Action({ eventOrigin: 'East Qorea' });

console.log("test threat:");
action.respondToThreat({ eventIsJustTest: true });
console.log("non-test threat:");
action.respondToThreat({});

如果你想防止程序员覆盖重要的方法,而不是 sub-classing 你可以只传递要执行的逻辑。在这种情况下,调用逻辑的 class 应该记录在什么情况下执行什么逻辑。传递的参数是什么以及预期的 return 值应该是什么。

以上可以通过多种不同的方式完成,这里是一个例子:

class Hooks {
  constructor(hooks, context) {
    this.hooks   = hooks;
    this.context = context;
  }
  
  find(...path) {
    let cursor = this.hooks;
    for (const key of path) {
      if (!cursor[key]) return this.noop;
      cursor = cursor[key];
    }
    return cursor.bind(this.context);
  }
  
  noop() {}
}

class NuclearStrategy {
  static withPresetHooks(hooks) {
    return (props) => new this({ ...props, hooks });
  }

  constructor(props) {
    this.eventOrigin = props.eventOrigin;
    this.hooks       = new Hooks(props.hooks || {}, this);
  }

  appeaseAllPopulation() {
    console.log('Broadcasting ');
  }

  respondToThreat({ eventIsJustTest }) {
    console.log(`✅ Appeasing the population`);
    this.hooks.find("respondToThreat", "eventIsJustTest", !!eventIsJustTest)();
  }
}

const createAction = NuclearStrategy.withPresetHooks({
  respondToThreat: {
    eventIsJustTest: {
      true: function () {
        console.log(`✅ Testing alert siren`);
      },
      false: function () {
        console.log(`✅ Playing alert siren`);
        console.log(`✅ Launched ICBM nuke to enemy`);
      },
    },
  },
});

const action = createAction({ eventOrigin: 'East Qorea' });

console.log("test threat:");
action.respondToThreat({ eventIsJustTest: true });
console.log("non-test threat:");
action.respondToThreat({});