如何在 NodeJS 中将事件添加到 derived/child class?

How to add events to a derived/child class in NodeJS?

我有一个 child class 扩展 parent class。我还希望 child class 能够发出事件。我发现的例子是扩展 EventEmitter。但是JS不允许多重继承。我试图通过 mixin 实现它,但不确定如何不将我的 parent class 转换为 mixin。

示例

假设有一个载具基地 class 所有车辆都会移动,有些车辆会在移动时发出事件

class Vehicle {
    constructor(name) { this.name = name }
    move() { console.log(this.name, 'Moved'); }
}

class Car extends Vehicle {
    constructor() { super('Ford'); }
    move() {
        super.move();
        this.engineSound();
    }
    engineSound() {
        console.log("Vroooom!");
    }
    // some other car related properties
}

class Ambulance extends Vehicle { // want to extend EventEmitter aswell
    constructor() { super('Ambulance1'); }
    move() {
        super.move();
        // emit moved event here
    }
}

let normalVehicle = new Vehicle('Normal');
normalVehicle.move();

let car = new Car();
car.move();

let ambulance = new Ambulance();
// Listen for moving ambulance here
// ambulance.on('moved', () => { console.log('Ambulance coming') });
ambulance.move();

但是要发出事件文档建议扩展 EventEmitter 但 JS 不支持扩展多个 classes。

看到几个使用 Object.assign 的示例,但不确定如何在此处应用。

es6 class 语法根本不支持多重继承。如果您将所有 classes 转换为 es5 构造函数,然后使用 Object.assign 之类的东西,您可以尝试一些奇怪的技巧。但最好的方法是使用组合而不是继承。

OOP 用于尝试模拟真实世界的对象,因此在现实世界中,救护车本身就是事件发射器也没有意义。

但是,使用组合方法,救护车 具有 事件发射器(如收音机或其他此类传输设备)是有意义的:

class Ambulance extends Vehicle {
    #radio = new EventEmitter();
    constructor() {
      super("Ambulance");
    }
    emit(event) { this.#radio.emit(event) }
    on(event, handler) { this.#radio.on(event, handler) }
    move() {
        super.move();
        this.emit("moved");
    }
}
let ambulance = new Ambulance();
ambulance.on('moved', () => { console.log('Ambulance coming') });
ambulance.move();

composition example

请注意,收音机是私有的(使用新的 JS 私有字段功能),我只为我希望救护车用户拥有的确切功能提供外观,在本例中 'on' 和 'emit'.


话虽如此...

让我们疯狂并实际回答您的问题!同样,这将需要使用 es5 构造函数:

// Base class - no inheritance
var Vehicle = (function () {
  function Vehicle(name) {
    this.name = name;
  }
  Vehicle.prototype.move = function () {
    return this.name + " Moved\n";
  };
  return Vehicle;
})();

// Derived from Vehicle - regular inheritance from a single object
var Car = (function (_super) {
  function Car() {
    // Calling super() in constructor
    _super.call(this, "Ford");
  }
  // extend Vehicle
  Car.prototype = Object.create(Vehicle.prototype);
  // bring back Car's constructor, because last step overrid it
  Object.defineProperty(Car.prototype, "constructor", {
    value: Car,
    enumerable: false,
    writable: true,
    configurable: true
  });
  Car.prototype.move = function () {
    return _super.prototype.move.call(this) + this.engineSound();
  };
  Car.prototype.engineSound = function () {
    return "Vroooom!\n";
  };
  return Car;
})(Vehicle);

// Derived from Vehicle and EventEmitter - multiple inheritance!
var Ambulance = (function (_superVehicle, _superEventEmitter) {
  function Ambulance() {
    _superVehicle.call(this, "Ambulance");
    _superEventEmitter.call(this);
  }

  // Create joint prototype using Object.assign
  var jointPrototype = Object.assign(
    {},
    _superEventEmitter.prototype,
    _superVehicle.prototype
  );
  // Connecting Ambulance to prototype chain
  Ambulance.prototype = Object.create(jointPrototype);
  // restore Ambulance's constructor
  Object.defineProperty(Ambulance.prototype, "constructor", {
    value: Ambulance,
    enumerable: false,
    writable: true,
    configurable: true
  });
  Ambulance.prototype.move = function () {
    this.emit("moved");
    return _superVehicle.prototype.move.call(this);
  };

  return Ambulance;
})(Vehicle, EventEmitter);

es5 multiple inheritance example