I was reading over this small article to understand inheriting from EventEmitter
, but I\'m a little confused.
He does this:
function Doo
The third example is not generally correct: that creates one single EventEmitter
instance for all door instances.
Let's imagine a simple case:
var Foo = function() {
// each Foo instance has a unique id
this.id = Math.random();
}
Foo.prototype.doFoo = function() { console.log("Foo!"); }
Suppose we want to create a Bar
constructor that inherits from Foo
and adds some new properties. If you follow your final example:
var Bar = function() {
this.something = 5;
}
Bar.prototype = new Foo();
This is wrong because all Bar
instance will have the same id
property. Instead, we must call the parent constructor for each instance:
var Bar = function() {
Foo.call(this); // set unique `id` on `this`
this.something = 5;
}
Bar.prototype = Object.create(Foo.prototype);
Note that the final line here is the same as Bar.prototype.__proto__ = Foo.prototype;
because Object.create
creates a new object whose __proto__
is set to the Object.create
argument.
The Node v6.3.1 documentation states about util.inherits(constructor, superConstructor):
Usage of
util.inherits()
is discouraged. Please use the ES6class
andextends
keywords to get language level inheritance support. Also note that the two styles are semantically incompatible.
The following code shows how to inherit from EventEmitter
with Typescript:
import { EventEmitter } from "events"
class Person extends EventEmitter {
constructor(public name: string) {
super()
}
}
let person = new Person("Bob")
person.on("speak", function (said: string) {
console.log(`${this.name} said: ${said}`)
})
person.emit("speak", "'hello'") // prints "Bob said: 'hello'"
The previous code will transpile into the following ES6 code:
"use strict";
const events = require("events");
class Person extends events.EventEmitter {
constructor(name) {
super();
this.name = name;
}
}
let person = new Person("Bob");
person.on("speak", function (said) { console.log(`${this.name} said: ${said}`); });
person.emit("speak", "'hello'");
Why does he manually invoke the EventEmitter constructor with his own constructor's this?
This is necessary to make sure whatever code is in the EventEmitter
constructor function is executed. Some classes might not do anything interesting in the constructor, but others will have important code there, so you should always do this to make sure that code runs the same way it would run if you had just made a new EventEmitter directly with var emitter = new EventEmitter;
In some languages (such as Java) this "constructor chaining" type behavior is implicit, but in JavaScript it must be explicitly done.
Exactly how to set up inheritance in JavaScript comes down to an "it's complicated" answer and others can probably do it more justice than I. There are also several viable variations and people differ on which is preferable. However, FYI the source for util.inherits is here and the best in-depth examination of all the flavors of doing this I have seen is in this video: Douglas Crockford: Advanced JavaScript. Basically, watch that in it's entirety periodically until it sinks in.
Places to look for reference. If you fully understand how all these works, you've mastered it (it still turns my brain into a pretzel at some point along the way)
function Door() {
events.EventEmitter.call(this);
}
Door.prototype.__proto__ = events.EventEmitter.prototype;
In this case using events.EventEmitter.call(this)
is like using super
in languages which have one. It's actually can be omitted in simple cases, but it will break domain
support on current node version and maybe something else in future versions.
Setting __proto__
just sets up the prototype chain. At can be also done like this:
Door.prototype = Object.create(events.EventEmitter.prototype);
but in this case you also need to set constructor
property manually.
util.inherits(Door, events.EventEmitter);
This is the idiomatic way of inheriting in node. So you are better to use this. But what it does is basically the same as above.
function Door() {
}
Door.prototype = new events.EventEmitter();
And this is the WRONG way, don't use it! You will end with having events shared between instances in some versions of node.