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?
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?
__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 de EventEmitter.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');
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' être masterInstance
.
Master.prototype = EventEmitter.prototype;
. Pas besoin de supers. Vous pouvez également utiliser les extensions ES6 (et c'est recommandé dans la documentation Node.js util.inherits
) comme ceci class Master extends EventEmitter
- vous obtenez du classique super()
, mais sans rien y injecter Master
.
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 dans MyEmitter
, 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.
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
) au Master.prototype
lieu de Master
demander au constructeur de la sous-classe d' appeler le super constructeur EventEmitter
; 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 objet Master
et ait par inadvertance également monkeypatched EventEmitter
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.
C'est ainsi que l'héritage prototypique (prototypique?) Se fait en JavaScript. De MDN :
Fait référence au prototype de l'objet, qui peut être un objet ou nul (ce qui signifie généralement que l'objet est Object.prototype, qui n'a pas de prototype). Il est parfois utilisé pour implémenter la recherche de propriétés basée sur l'héritage de prototype.
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.
Y.prototype = new X();
est un anti-motif, veuillez utiliserY.prototype = Object.create(X.prototype);
new X()
instancie une instance de X.prototype
et l'initialise en l'invoquant X
. Object.create(X.prototype)
instancie simplement une instance. Vous ne souhaitez Emitter.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
emit
et on
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
util.inherits
car beaucoup de gens intelligents garderont ces options à jour pour vous.