98 votes

Node.js - héritant de EventEmitter

Je vois ce modèle dans pas mal de bibliothèques Node.js:

 Master.prototype.__proto__ = EventEmitter.prototype;
 

(source ici )

Quelqu'un peut-il m'expliquer s'il vous plaît avec un exemple, pourquoi c'est un modèle si commun et quand c'est pratique?

96voto

alessioalex Points 27001

Comme le dit le commentaire ci-dessus, ce code fera hériter Master de EventEmitter.prototype sorte que vous pouvez utiliser des instances de cette 'classe' pour émettre et écouter des événements.

Par exemple, vous pouvez maintenant faire:

 masterInstance = new Master();

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

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

Mise à jour : comme de nombreux utilisateurs l'ont souligné, la méthode "standard" pour ce faire dans Node consiste à utiliser "util.inherits":

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

41voto

metamatt Points 3276

Pour hériter d'un autre objet Javascript, Node.js's EventEmitter en particulier, mais vraiment tout objet en général, vous devez faire deux choses:

  • fournir un constructeur pour votre objet, qui a complètement initialise l'objet; dans le cas que vous êtes à hériter de quelque autre objet, vous voulez probablement à déléguer une partie de cette initialisation de travail pour le super constructeur.
  • fournir un prototype de l'objet qui sera utilisé comme l' [[proto]] pour les objets créés à partir de votre constructeur; dans le cas que vous êtes à hériter de quelque autre objet, vous voudrez probablement utiliser une instance de l'autre objet que votre prototype.

C'est plus compliqué en Javascript qu'il n'y paraît dans d'autres langues parce que

  • Javascript sépare le comportement des objets en "constructeur" et "prototype". Ces concepts sont conçus pour être utilisés ensemble, mais peuvent être utilisés séparément.
  • Javascript est un très malléable, la langue et les gens l'utilisent différemment et il n'existe pas de véritable définition de ce qu'est "l'héritage".
  • Dans de nombreux cas, il peut s'en sortir en faisant un sous-ensemble de ce qui est correct, et vous trouverez des tonnes d'exemples à suivre (y compris certains autres réponses à cette SORTE de question) qui semblent bien fonctionner pour votre cas.

Pour le cas spécifique de Node.js's EventEmitter, voici ce qui fonctionne:

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);

Possible faiblesses:

  • Si vous utilisez set le prototype de votre sous-classe (Maître.prototype), avec ou sans l'aide d' util.inherits, mais ne l'appelez pas la super constructeur (EventEmitter) pour les instances de votre classe, ils ne sont pas correctement initialisé.
  • Si vous appelez la super constructeur mais ne réglez pas le prototype, EventEmitter méthodes ne fonctionnent pas sur votre objet
  • Vous pouvez essayer d'utiliser un initialisé instance de la super-classe (new EventEmitter) Master.prototype au lieu d'avoir le sous-classe constructeur Master appelez le super constructeur EventEmitter; selon le comportement de la superclasse constructeur qui peut sembler comme il fonctionne bien pendant un certain temps, mais n'est pas la même chose (et ne fonctionnera pas pour EventEmitter).
  • Vous pouvez essayer d'utiliser le super prototype directement (Master.prototype = EventEmitter.prototype) au lieu d'ajouter une couche supplémentaire de l'objet par Objet.créer; ce qui pourrait sembler comme s'il fonctionne bien jusqu'à ce que quelqu'un monkeypatches votre objet Master et a, par inadvertance, aussi monkeypatched EventEmitter et tous ses autres descendants. Chaque "classe" doit avoir son propre prototype.

Nouveau: pour hériter de EventEmitter (ou vraiment tout objet existant "classe"), que vous souhaitez définir un constructeur qui est lié à la super constructeur et fournit un prototype qui est dérivé de la super prototype.

19voto

Daff Points 22358

C'est de cette façon prototypique (prototypes?) l'héritage est fait en JavaScript. De MDN:

Désigne le prototype de l'objet, qui peut être un objet ou une valeur null (ce qui signifie généralement l'objet est l'Objet.prototype, qui n'a pas de prototype). Il est parfois utilisé pour mettre en œuvre prototype-l'héritage base de recherche de propriété.

Cela fonctionne ainsi:

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

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

La compréhension de la programmation orientée objet en JavaScript est l'un des meilleurs articles que j'ai lus ces derniers temps sur la programmation orientée objet en ECMAScript 5.

5voto

wprl Points 6139

J'ai pensé que cette démarche de http://www.bennadel.com/blog/2187-Extending-EventEmitter-To-Create-An-Evented-Cache-In-Node-js.htm a été assez soignée:

function EventedObject(){

  // Super constructor
  EventEmitter.call( this );

  return( this );

}

Douglas Crockford a quelques intéressants héritage des modèles trop: http://www.crockford.com/javascript/inheritance.html

Je trouve l'héritage est moins souvent nécessaire en JavaScript et Node.js. Mais dans l'écriture d'une application, où l'héritage pourrait affecter l'évolutivité, je voudrais prendre en compte les performances pesé à l'encontre de la maintenabilité. Sinon, je tiens seulement à la base de ma décision sur les motifs qui conduisent à l'amélioration d'ensemble de conceptions, sont plus facile à gérer et moins sujette aux erreurs.

L'essai de différents modèles dans jsPerf, à l'aide de Google Chrome (V8) pour faire une bonne comparaison. V8 est le moteur JavaScript utilisé par les deux Node.js et Chrome.

Voici quelques jsPerfs pour vous aider à démarrer:

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

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

http://jsperf.com/inheritance-perf

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X