1

I have been following Hands-On Node.js by by Manuel Teixiera and I stumbled upon this weird behaviour while going through the Event Emitter chapter.

The code suggested by the author consists of something like this:

var EventEmitter = require("events").EventEmitter;
var util = require ("util");

var MyClass = function() {};
util.inherits(MyClass, EventEmitter);
var instance = new MyClass();
instance.on("custom", function() {
   console.log("Holo");
});

instance.emit("custom");*/

Which outputs "Holo" just fine. However, I have also read documentation and SO questions on the subject of how using new Function(); is an anti-pattern that flies in the face of javascript's intended use of prototypical inheritance. This article by David Walsh illustrates the difference between forcing classical inheritance on js and using its capabilities for prototypical inheritance.

So, I tried modify my code by re-writing it like so:

var EventEmitter = require("events").EventEmitter;
var clock = {};
util.inherits(clock, EventEmitter);
clock.on("custom", function(){
    console.log("Holo");
});
clock.emit("custom");

I get an error saying TypeError: Object object has no method 'on'. I don't understand why is this, since I have created the clock object with the util.inherit() helper. The same code using var clock = Object.create(EventEmitter) doesn't work either.

The only instance where I can get the code to work is this:

var EventEmitter = require("events").EventEmitter;
var util = require("util");
var clock = {};
util.inherits(clock, EventEmitter);
clock.prototype.on("custom", function(){
    console.log("Holo");
});
clock.emit = function(){
        clock.prototype.emit("custom");
}
clock.emit();

This outputs "Holo" just fine. The thing is, i don't understand why do I need to access the prototype to set an Event Listener or emit an Event when, supposedly, I made the clock variable delegate it's methods to the EventEmitter object, so they should work fine without the prototype notation.

Would you please help me?

Community
  • 1
  • 1
Eduardo de Luna
  • 501
  • 1
  • 4
  • 14

2 Answers2

3

According to the node.js docs:

util.inherits(constructor, superConstructor)

Inherit the prototype methods from one constructor into another. The prototype of constructor will be set to a new object created from superConstructor.

You are passing in an object where util.inherits was designed to expect a constructor. util.inherits operates by redefining the constructor's prototype property, which has prototype chain implications for instances constructed by that constructor. Instead of a constructor function, you have passed in an object, which has its prototype property altered. This has no implications for anyting: you've just created a property on the object called "prototype", which is exactly as special as if you'd made a property on the object called foobar.

There is a school of thought that eschews use of new (in favor of factory functions that call Object.create -- see discussion on Is JavaScript's "new" keyword considered harmful?), but evidently the API designers who implemented util.inherits do not share that view.

Your attempted Object.create(EventEmitter) is indeed not correct, however, because Object.create expects a prototype object, not a constructor function. Instead, you'd do Object.create(EventEmitter.prototype). This is the same as calling new EventEmitter(), except that the Object.create variant does not call the EventEmitter constructor function.

Community
  • 1
  • 1
apsillers
  • 112,806
  • 17
  • 235
  • 239
0

I don't know the implementation of Node's inherit until, but I imagine it simply adds members to the first operand's prototype from the second. It therefore assumes it will be passed a constructor. But passing an empty object will not throw an exception.

You will need to pass a constructor function and call it with new. This is normal and absolutely fine.

Also, where did you get the idea that using new and prototypes were somehow mutually exclusive, or that New is to be avoided? It sounds like you might want to practice your JavaScript OOP a little more.

Jimmy Breck-McKye
  • 2,923
  • 1
  • 22
  • 32
  • It's not that using new and prototype are mutually exclusive, it's just that in the documentation and discussions I've read so far, including the one @apsillers is referencing, constructor function use for inheritance makes code that is, IMHO, obfuscated and hard to understand. I'm not saying it's not okay, evidently the creators of the Node.js api think it is. It's just something that I find hard to piece together. Admittedly, I'm very new to JS. – Eduardo de Luna May 12 '14 at 20:08
  • @EduardodeLuna - the docs that Aspillers refers to complain that constructors, if called incorrectly, will pollute the global namespace. That's all. Nothing to do with 'flying in the face of prototypical inheritance' (New'ed objects still have prototypes), and I can't see anything 'obfuscated' about idiomatic JavaScript. You cannot avoid using New - you **cannot** use private object variables, accessors or protecteds in JavaScript without constructor functions. OOP without encapsulation is practically pointless. – Jimmy Breck-McKye May 12 '14 at 20:18