Узел.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
и непреднамеренно также monkeypatchedEventEmitter
и все остальные его потомки. Каждый" класс " должен иметь свой прототип.
снова: чтобы наследовать от 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
чтобы добавить к ответу wprl. Он пропустил часть "прототипа":
function EventedObject(){
// Super constructor
EventEmitter.call(this);
return this;
}
EventObject.prototype = new EventEmitter(); //<-- you're missing this part