Je vois ce modèle dans de nombreuses bibliothèques Node.js:
Master.prototype.__proto__ = EventEmitter.prototype;
(source ici )
Quelqu'un peut-il m'expliquer avec un exemple, pourquoi c'est un modèle si courant et quand c'est pratique?
node.js
eventemitter
Jeffreyveon
la source
la source
__proto__
est un anti-motif, veuillez utiliserMaster.prototype = Object.create(EventEmitter.prototype);
util.inherits(Master, EventEmitter);
Réponses:
Comme le commentaire ci-dessus ce code l'indique, il
Master
héritera deEventEmitter.prototype
, vous pouvez donc 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 manière `` standard '' de faire cela dans Node serait d'utiliser `` util.inherits '':
var EventEmitter = require('events').EventEmitter; util.inherits(Master, EventEmitter);
2ème mise à jour : avec les classes ES6 à nos portes, il est recommandé d'étendre la
EventEmitter
classe maintenant:const EventEmitter = require('events'); class MyEmitter extends EventEmitter {} const myEmitter = new MyEmitter(); myEmitter.on('event', () => { console.log('an event occurred!'); }); myEmitter.emit('event');
Voir https://nodejs.org/api/events.html#events_events
la source
require('events').EventEmitter
premier, j'oublie toujours. Voici le lien vers la documentation au cas où quelqu'un d'autre en aurait besoin: nodejs.org/api/events.html#events_class_events_eventemitter )MasterInstance
devrait donc l' êtremasterInstance
.util.inherits
fait une mauvaise chose en injectant lasuper_
propriété dans l'Master
objet. C'est inutile et essaie de traiter l'héritage prototypique comme l'héritage classique. Jetez un œil au bas de cette page pour obtenir des explications.Master.prototype = EventEmitter.prototype;
. Pas besoin de supers. Vous pouvez également utiliser les extensions ES6 (et c'est recommandé dans la documentation Node.jsutil.inherits
) comme ceciclass Master extends EventEmitter
- vous obtenez du classiquesuper()
, mais sans rien y injecterMaster
.Héritage de classe de style ES6
La documentation Node recommande maintenant d' utiliser l'héritage de classe pour créer votre propre émetteur d'événements:
const EventEmitter = require('events'); class MyEmitter extends EventEmitter { // Add any custom methods here } const myEmitter = new MyEmitter(); myEmitter.on('event', () => { console.log('an event occurred!'); }); myEmitter.emit('event');
Remarque: Si vous définissez une
constructor()
fonction dansMyEmitter
, vous devez appeler àsuper()
partir de celle-ci pour vous assurer que le constructeur de la classe parente est également appelé, sauf si vous avez une bonne raison de ne pas le faire.la source
super()
n'est pas nécessaire , tant que vous n'avez pas besoin / définissez un constructeur, donc la réponse originale de Breedly (voir l'historique EDIT) était entièrement correcte. Dans ce cas, vous pouvez copier et coller ce même exemple dans le repl, supprimer entièrement le constructeur et cela fonctionnera de la même manière. C'est une syntaxe parfaitement valide.Pour hériter d'un autre objet Javascript, EventEmitter de Node.js en particulier mais vraiment de n'importe quel objet en général, vous devez faire deux choses:
[[proto]]
pour les objets créés à partir de votre constructeur; dans le cas où vous héritez d'un autre objet, vous voudrez probablement utiliser une instance de l'autre objet comme prototype.C'est plus compliqué en Javascript qu'il n'y paraît dans d'autres langues car
Pour le cas spécifique de l'EventEmitter de Node.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:
util.inherits
, mais n'appelez pas le super constructeur (EventEmitter
) pour les instances de votre classe, elles ne seront pas correctement initialisées.new EventEmitter
) auMaster.prototype
lieu deMaster
demander au constructeur de la sous-classe d' appeler le super constructeurEventEmitter
; en fonction du comportement du constructeur de la superclasse, cela peut sembler fonctionner correctement pendant un certain temps, mais ce n'est pas la même chose (et ne fonctionnera pas pour EventEmitter).Master.prototype = EventEmitter.prototype
) au lieu d'ajouter une couche d'objet supplémentaire via Object.create; cela peut sembler fonctionner correctement jusqu'à ce que quelqu'un attrape votre objetMaster
et ait par inadvertance également monkeypatchedEventEmitter
et tous ses autres descendants. Chaque «classe» doit avoir son propre prototype.Encore une fois: pour hériter d'EventEmitter (ou vraiment de n'importe quel objet "classe" existant), vous voulez définir un constructeur qui s'enchaîne au super constructeur et fournit un prototype dérivé du super prototype.
la source
C'est ainsi que l'héritage prototypique (prototypique?) Se fait en JavaScript. De MDN :
Cela fonctionne également:
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 récemment sur la POO dans ECMAScript 5.
la source
Y.prototype = new X();
est un anti-motif, veuillez utiliserY.prototype = Object.create(X.prototype);
new X()
instancie une instance deX.prototype
et l'initialise en l'invoquantX
.Object.create(X.prototype)
instancie simplement une instance. Vous ne souhaitezEmitter.prototype
pas être initialisé. Je ne trouve pas un bon article qui explique cela.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ée:
function EventedObject(){ // Super constructor EventEmitter.call( this ); return( this ); }
Douglas Crockford a également 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 dans JavaScript et Node.js. Mais en écrivant une application où l'héritage pourrait affecter l'évolutivité, je considérerais les performances mises en balance avec la maintenabilité. Sinon, je baserais ma décision uniquement sur les modèles qui conduisent à de meilleures conceptions globales, sont plus faciles à entretenir 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é à la fois par 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
la source
emit
eton
sont à venir comme indéfinies.Pour ajouter à la réponse de wprl. Il a raté la partie "prototype":
function EventedObject(){ // Super constructor EventEmitter.call(this); return this; } EventObject.prototype = new EventEmitter(); //<-- you're missing this part
la source
util.inherits
car beaucoup de gens intelligents garderont ces options à jour pour vous.