Как расширить объектно-буквальные объекты для событий в NodeJS?

Я пытаюсь передать события объекта Node.js. Теперь это не проблема, если я создаю «статические» объекты и создаю их экземпляры, но как мне это сделать, если у моего объекта нет статического дедушки, например, когда объект был создан с использованием нотации литерала объекта?

Я привык писать синтаксис ExtJS, поэтому предпочитаю все в объектном литерале.

// var EventEmitter = require('events').EventEmitter; // How where when?

myObject = {
  myFunction: function() {
    console.log('foo');
  },
  urFunction: function() {
    console.log('bar');
  }
};

Это объект. У него нет конструктора, потому что не нужно больше экземпляров.

Как теперь разрешить myObject генерировать события?

Я пытался адаптировать код, но я не могу заставить его работать, не переписав свой объект в форму с помощью конструктора, например:

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

function myClass() {
  EventEmitter.call(this);

  myFunction: function() {
    this.emit('foo');
  },
  urFunction: function() {
    this.emit('bar');
  }
};

myClass.prototype = Object.create(EventEmitter.prototype);
// or // util.inherits(myClass, EventEmitter);
var myObject = new myClass; // Shouldn't be necessary for my single-instance case

Или добавление моих функций / прототипов к чему-то построенному следующим образом:

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

var myObject = new EventEmitter();
// or // var myObject = Object.create(new EventEmitter); // Dunno difference
myObject.myFunction = function() {
    this.emit('foo');
  },
myObject.urFunction = function() {
    this.emit('bar');
  }
};

util.inherits(myObject, EventEmitter);

Как разрешить myObject генерировать события, сохранив буквальную нотацию объекта? Так много запутанных способов сделать это, но ни одного в этих JSON- подобных объектах с пометкой.


person Redsandro    schedule 31.05.2012    source источник
comment
Очень хороший вопрос, мне нравится использовать Object.create () и литералы из сред на основе браузера, но пока я использую node js в течение некоторого времени, я пришел к выводу, что обработка объектов, подобная ES5, несколько недоиспользуется. Причина может заключаться в том, что такие функции, как util.inherits, не существуют для обработки объектных литералов.   -  person vanthome    schedule 27.03.2013
comment
См. Этот ответ: stackoverflow.com/questions/24925115/   -  person victorwoo    schedule 25.07.2014


Ответы (3)


Почему бы не использовать композицию вместо наследования?

var myObject = {
  myFunction: function() {
    console.log('foo');
  },
  urFunction: function() {
    console.log('bar');
  },
  emitter: new EventEmitter()
}
person ziad-saab    schedule 01.06.2012
comment
Выглядит интересно. Является ли «внутренний» эмиттер таким же «публичным», как когда myObject был бы эмиттером? Например. Я могу сделать это из корневой функции self.myObject.emitter.on('customEvent', doSomethinG()); (если, конечно, self = this установлен в том же корне)? - person Redsandro; 01.06.2012
comment
да. И если вы хотите, чтобы ваш объект крякал, как эмиттер, вы даже можете добавить некоторые из функций эмиттера, которые вы будете использовать, например `var myObject = {... emitter: new EventEmitter (), emit: myObject.emitter.emit, on: myObject.emitter.on, ...} - person ziad-saab; 01.06.2012
comment
Умный. Просто любопытно, насколько это универсально: могу ли я каким-то образом передать эмиттер из отдельной функции / области видимости и получить такое же удовольствие? Например. запрос nodejs запускает onRequest(), который что-то делает с myObject, что вызывает события, которые прослушиваются внутри onRequest(). Теперь второй (третий и n -й) одновременный запрос делает то же самое, но должен только прослушивать события, вызванные их собственной игрой с myObject. Для этого onRequest() потребуется передавать новый эмиттер myObject каждый раз, иначе события myObject будут перехвачены каждым запущенным экземпляром onRequest(). - person Redsandro; 01.06.2012
comment
Я не уверен, что понимаю ваш последний вопрос на 100%. Но посмотрите на это с другой стороны: вы наследуете все функции EventEmitter. Но вместо того, чтобы наследовать их путем расширения EventEmitter, вы наследуете их, добавляя EventEmitter как часть вашего объекта. - person ziad-saab; 01.06.2012

К сожалению, желаемый синтаксис объектного литерала невозможен. Это потому что

var obj = {};

эквивалентно

var obj = Object.create(Object.prototype);

в этом прототипе obj зафиксировано значение Object.prototype при создании, и вы не можете изменить это позже.

Поскольку вам нужен только один экземпляр, я бы сказал, что действительно имеет смысл создать экземпляр EventEmitter и назначить ему свойства:

var EventEmitter = require('events').EventEmitter;
var obj = new EventEmitter();

obj.doStuff = function() {
  this.emit('stuff');
};

Здесь вам не нужно util.inherits, так как у вас всего один экземпляр, поэтому нет цепочки для настройки.

person J. Ryan Stinnett    schedule 01.06.2012
comment
Спасибо за объяснение части, касающейся prototype. Я лишь частично понял, что происходит, и подумал, что {} был сокращением для определения и создания экземпляра объекта без конструктора. Знаете ли вы более естественный способ присвоения свойств экземпляру EventEmitter, чтобы мне было легче переносить на них свой object literals, как указано в моем первом комментарии к Маттиасу Буэленсу? - person Redsandro; 01.06.2012
comment
Мне неизвестен родной способ расширения с помощью литерала объекта. Однако включение jQuery не идеально подходит для проекта node.js, поскольку большая часть jQuery предназначена для управления DOM. Я бы посоветовал включить такую ​​служебную библиотеку, как Lo-Dash или Подчеркивание. Вы можете установить это с помощью npm. - person J. Ryan Stinnett; 01.06.2012
comment
Очень хорошее объяснение, но ваше предлагаемое решение не имеет смысла, если вы создаете многоразовую библиотеку. В этом случае вы не захотите добавлять функции после построения. - person vanthome; 27.03.2013
comment
Если у jQuery есть такая вещь, не могли бы вы просто попытаться найти соответствующие части из js-файла jQuery и скопировать только их? - person Julix; 25.08.2018

Это совершенно безумная догадка, поскольку я написал только JavaScript для браузеров. Однако нельзя ли просто вызвать EventEmitter для своего объекта после создания литерала объекта?

myObject = {
    myFunction: function() {
        console.log('foo');
    },
    urFunction: function() {
        console.log('bar');
    }
};
EventEmitter.call(myObject);
person Mattias Buelens    schedule 31.05.2012
comment
Хотелось бы, чтобы это было так просто, но, к сожалению, это не работает. Грязный способ имитировать превращение моего object literal в EventEmitter - это заимствовать jQuery extend (), например итак: var myObject = new EventEmitter(); $.extend(myClass, myObject); где myClass - мой object literal. Очевидно ищу более родной способ. - person Redsandro; 01.06.2012