Nœud.js-hériter de EventEmitter

Je vois ce modèle dans un certain nombre de nœuds.bibliothèques js:

Master.prototype.__proto__ = EventEmitter.prototype;

(source ici)

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

77
demandé sur jeffreyveon 2012-01-17 20:44:46

6 réponses

Comme le dit le commentaire ci-dessus, Master héritera de EventEmitter.prototype, de 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');

Update : comme de nombreux utilisateurs l'ont souligné, la manière 'standard' de le faire dans Node serait d'utiliser 'util.hérite":

var EventEmitter = require('events').EventEmitter;
util.inherits(Master, EventEmitter);
78
répondu alessioalex 2014-07-08 07:01:18

ES 6 héritage de classe de Style

Ceux-ci viennent directement des docs, mais je me suis dit que ce serait bien de les ajouter à cette question populaire pour ceux qui cherchent.

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

J'aimerais git thank Celui qui a ajouté cela. Émetteur D'Événement .

Note: la documentation n'appelle pas super() dans le constructeur, ce qui rendra this indéfini. Voir ce problème .

61
répondu Breedly 2018-09-24 09:22:07

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

  • fournissez un constructeur pour votre objet, qui initialise complètement l'objet; dans le cas où vous héritez d'un autre objet, vous voulez probablement déléguer une partie de ce travail d'initialisation au super constructeur.
  • fournissez un objet prototype qui sera utilisé comme [[proto]] pour les objets créés à partir de votre constructeur; dans le cas où vous héritez d'un autre objet, vous voulez probablement utiliser une instance de l'autre objet comme prototype.

C'est plus compliqué en Javascript que cela puisse paraître dans d'autres langages Car

  • Javascript sépare le comportement de l'objet 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 langage très malléable et les gens l'utilisent différemment et il n'y a pas de véritable définition unique de ce que signifie "héritage".
  • dans de nombreux cas, vous pouvez vous en sortir en faisant un sous-ensemble de ce qui est correct, et vous trouverez des tonnes d'exemples à suivre (y compris d'autres réponses à cette question SO) qui semblent bien fonctionner pour votre cas.

Pour le cas spécifique de Nœud.L'EventEmitter DE js, 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);

Faiblesses possibles:

  • Si vous utilisez définir le prototype de votre sous-classe (Maître.prototype), avec ou sans utiliser util.inherits, mais n'appelez pas le super constructeur (EventEmitter) pour les instances de votre classe, elles ne seront pas correctement initialisées.
  • Si vous appelez le super constructeur mais Ne définissez pas le prototype, les méthodes EventEmitter ne fonctionneront pas sur votre objet
  • Vous pouvez essayer d'utiliser une instance initialisée de la superclasse (new EventEmitter) comme Master.prototype au lieu d'avoir le constructeur de la sous-classe Master appeler le super constructeur EventEmitter; en fonction du comportement du constructeur de superclasse qui peut sembler fonctionner correctement pendant un certain temps, mais ce n'est pas la même chose (et ne fonctionnera pas pour EventEmitter).
  • , Vous pouvez utiliser le super prototype directement (Master.prototype = EventEmitter.prototype) au lieu d'ajouter une couche supplémentaire de l'objet par Objet.create; cela peut sembler fonctionner correctement jusqu'à ce que quelqu'un monkeypatches votre objet Master et a par inadvertance aussi monkeypatched EventEmitter et tous ses autres descendants. Chaque" classe " devrait avoir sa propre prototype.

Encore une fois: pour hériter D'EventEmitter (ou vraiment de toute "classe" d'objet existant), vous voulez définir un constructeur qui enchaîne au super constructeur et fournit un prototype dérivé du Super prototype.

36
répondu metamatt 2014-05-28 17:55:53

C'est comment prototypique (prototypique?) l'héritage se fait en JavaScript. À partir de MDN:

Fait référence au prototype de l'objet, qui peut être un objet ou null (ce qui signifie généralement que l'objet est objet.prototype, qui n'a pas de prototype). Il est parfois utilisé pour implémenter l'héritage prototype recherche de propriété basée.

Cela fonctionne aussi:

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

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

Comprendre JavaScript OOP est l'un des meilleurs articles que j'ai lus dernièrement sur OOP dans ECMAScript 5.

19
répondu Daff 2014-06-13 14:46:30

Je pensais que cette approche de http://www.bennadel.com/blog/2187-Extending-EventEmitter-To-Create-An-Evented-Cache-In-Node-js.htm était assez soigné:

function EventedObject(){

  // Super constructor
  EventEmitter.call( this );

  return( this );

}

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

Je trouve que l'héritage est moins souvent nécessaire en JavaScript et Node.js. Mais en écrivant une application où l'héritage pourrait affecter l'évolutivité, je considérerais les performances pesées maintenabilité. Sinon, je ne baserais ma décision que sur les modèles qui conduisent à de meilleures conceptions globales, sont plus maintenables et moins sujets aux erreurs.

Testez différents modèles dans jsPerf, en utilisant Google Chrome (V8) pour obtenir une comparaison approximative. V8 est le moteur JavaScript utilisé par les deux nœuds.js et Chrome.

Voici quelques jsPerfs pour vous commencé:

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

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

Http://jsperf.com/inheritance-perf

5
répondu wprl 2013-03-01 16:50:50

À ajouter à la réponse de wprl. Il a manqué la partie "prototype":

function EventedObject(){

   // Super constructor
   EventEmitter.call(this);

   return this;

}
EventObject.prototype = new EventEmitter(); //<-- you're missing this part
1
répondu guatedude2 2016-06-03 20:47:19