Узел.JS-наследование от EventEmitter

Я вижу этот шаблон в довольно многих узлах.библиотеки js:

Master.prototype.__proto__ = EventEmitter.prototype;

(source здесь)

может кто-нибудь объяснить мне на примере, почему это такой распространенный шаблон и когда это удобно?

6 ответов


как говорится в комментарии выше этого кода, он сделает Master наследовать от EventEmitter.prototype, Так что вы можете использовать экземпляры этого класса для передачи и прослушивания событий.

например, теперь вы можете сделать:

masterInstance = new Master();

masterInstance.on('an_event', function () {
  console.log('an event has happened');
});

// trigger the event
masterInstance.emit('an_event');

обновление: как указывали многие пользователи, "стандартным" способом сделать это в узле было бы использовать " util.наследует':

var EventEmitter = require('events').EventEmitter;
util.inherits(Master, EventEmitter);

ES 6 наследование класса стиля

они приходят прямо из документов, но я подумал, что было бы неплохо добавить их к этому популярному вопросу для тех, кто ищет.

const EventEmitter = require('events');

class MyEmitter extends EventEmitter {
  constructor() {
    super(); //must call super for "this" to be defined.
  }
}

const myEmitter = new MyEmitter();
myEmitter.on('event', () => {
  console.log('an event occurred!');
});
myEmitter.emit('event');

Я хочу git thank кто бы это ни добавил. Излучатель Событие.

Примечание: документация не вызывает super() в конструкторе, который вызовет this чтобы быть неопределенным. Смотрите это вопрос.


для наследования от другого объекта Javascript, Node.EventEmitter js в частности, но действительно любой объект в целом, вам нужно сделать две вещи:

  • предоставьте конструктор для вашего объекта, который полностью инициализирует объект; в случае, если вы наследуете от какого-либо другого объекта, вы, вероятно, хотите делегировать часть этой работы инициализации супер конструктору.
  • предоставьте объект прототипа, который будет использоваться как [[proto]] для объекты, созданные из вашего конструктора; в случае, если вы наследуете от какого-либо другого объекта, вы, вероятно, хотите использовать экземпляр другого объекта в качестве прототипа.

это сложнее в Javascript, чем может показаться на других языках, потому что

  • Javascript разделяет поведение объекта на "конструктор"и " прототип". Эти понятия предназначены для совместного использования, но могут использоваться отдельно.
  • Javascript является очень податливый язык, и люди используют его по-разному, и нет единого истинного определения того, что означает" наследование".
  • во многих случаях вы можете уйти от выполнения подмножества того, что правильно, и вы найдете множество примеров, чтобы следовать (включая некоторые другие ответы на этот вопрос SO), которые, похоже, отлично работают для вашего случая.

для конкретного случая узел.EventEmitter js, вот что работает:

var EventEmitter = require('events').EventEmitter;
var util = require('util');

// Define the constructor for your derived "class"
function Master(arg1, arg2) {
   // call the super constructor to initialize `this`
   EventEmitter.call(this);
   // your own initialization of `this` follows here
};

// Declare that your class should use EventEmitter as its prototype.
// This is roughly equivalent to: Master.prototype = Object.create(EventEmitter.prototype)
util.inherits(Master, EventEmitter);

возможно слабости:

  • если вы используете set прототип для вашего подкласса (Master.прототип), с использованием или без использования util.inherits, но не вызывайте супер конструктор (EventEmitter) для экземпляров вашего класса они не будут правильно инициализированы.
  • если вы вызываете супер конструктор, но не устанавливаете прототип, методы EventEmitter не будут работать на вашем объекте
  • вы можете попробовать использовать инициализированный экземпляр суперкласса (new EventEmitter) как Master.prototype вместо наличие конструктора подкласса Master звонок супер конструктор EventEmitter; в зависимости от поведения конструктора суперкласса, который может показаться, что он работает нормально некоторое время, но это не одно и то же (и не будет работать для EventEmitter).
  • вы можете попробовать использовать супер прототип напрямую (Master.prototype = EventEmitter.prototype) вместо добавления дополнительного слоя объекта через объект.создать; это может показаться, что он работает нормально, пока кто-то monkeypatches ваш объект Master и непреднамеренно также monkeypatched EventEmitter и все остальные его потомки. Каждый" класс " должен иметь свой прототип.

снова: чтобы наследовать от EventEmitter (или действительно любого существующего объекта "class"), вы хотите определить конструктор, который цепляется к супер конструктору и предоставляет прототип, производный от супер прототипа.


Это как прототипический (prototypal?) наследование выполняется в JavaScript. От MDN:

относится к прототипу объекта, который может быть объектом или null (что обычно означает, что объект является объектом.прототип, который не имеет прототип.) Иногда он используется для реализации прототипа-наследования поиск свойств на основе.

Это также работает:

var Emitter = function(obj) {
    this.obj = obj;
}

// DON'T Emitter.prototype = new require('events').EventEmitter();
Emitter.prototype = Object.create(require('events').EventEmitter.prototype);

понимание JavaScript ООП - один из лучших статей, которые я читал в последнее время на ООП в ECMAScript 5.


Я думал, что этот подход от http://www.bennadel.com/blog/2187-Extending-EventEmitter-To-Create-An-Evented-Cache-In-Node-js.htm было довольно аккуратно:

function EventedObject(){

  // Super constructor
  EventEmitter.call( this );

  return( this );

}

у Дугласа Крокфорда тоже есть интересные шаблоны наследования:http://www.crockford.com/javascript/inheritance.html

Я считаю, что наследование реже требуется в JavaScript и Node.js. Но при написании приложения, где наследование может повлиять на масштабируемость, я бы рассмотрите производительность, взвешенную против ремонтопригодности. В противном случае, я бы только основывал свое решение на том, какие шаблоны приводят к улучшению общего дизайна, более ремонтопригодны и менее подвержены ошибкам.

Проверьте различные шаблоны в jsPerf, используя Google Chrome (V8), чтобы получить грубое сравнение. V8-это движок JavaScript, используемый обоими узлами.js и Chrome.

вот некоторые jsPerfs для вас начал:

http://jsperf.com/prototypes-vs-functions/4

http://jsperf.com/inheritance-proto-vs-object-create

http://jsperf.com/inheritance-perf


чтобы добавить к ответу wprl. Он пропустил часть "прототипа":

function EventedObject(){

   // Super constructor
   EventEmitter.call(this);

   return this;

}
EventObject.prototype = new EventEmitter(); //<-- you're missing this part