Узел.js-наследование от EventEmitter
Я вижу этот шаблон в довольно многих узлах.библиотеки js:
Master.prototype.__proto__ = EventEmitter.prototype;
(источник здесь)
может кто-нибудь объяснить мне на примере, почему это такой распространенный шаблон и когда это удобно?
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.JS EventEmitter в частности, но на самом деле любой объект в целом, вам нужно сделать две вещи:
- предоставьте конструктор для вашего объекта, который полностью инициализирует объект; в случае, если вы наследуете от какого-либо другого объекта, вы, вероятно, захотите делегировать часть этой работы инициализации суперконструктору.
- предоставить прототип объекта, который будет использоваться в качестве
[[proto]]для объекты, созданные из конструктора; в случае, если вы наследуете от какого-либо другого объекта, вы, вероятно, хотите использовать экземпляр другого объекта в качестве прототипа.это сложнее в Javascript, чем может показаться на других языках, потому что
- Javascript разделяет поведение объекта на" конструктор "и"прототип". Эти понятия предназначены для использования вместе, но могут использоваться отдельно.
- Javascript - это очень податливый язык, и люди используют его по-разному, и нет единого истинного определения того, что означает "наследование".
- во многих случаях вам может сойти с рук выполнение подмножества того, что правильно, и вы найдете множество примеров для подражания (включая некоторые другие ответы на этот вопрос SO), которые, похоже, отлично работают для вашего случая.
для конкретного случая узел.JS EventEmitter, вот что работает:
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) вместо добавления дополнительного слоя объекта через объект.создать; это может показаться, что он работает нормально, пока кто-то обезьяны не заберет ваш объектMasterи по неосторожности тоже обезьянкаEventEmitterи все остальные его потомки. Каждый "класс" должен иметь свой собственный прототип.опять же: чтобы наследовать от EventEmitter (или действительно любого существующего объекта "class"), вы хотите определить конструктор, который связывается с супер-конструктором и предоставляет прототип, который является производным от супер-прототипа.
Это как прототипический (прототипный?) наследование выполняется в 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 и хром.
вот некоторые 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
Comments