Search code examples
javascriptnode.jseventseventemitter

Node.js - Best method for emitting events from modules


I've been playing around with the EventEmitter, but I'm confused about how exactly I should implement it from a module. I've seen a few different ways, and they all seem to work. Here are a few I've seen:

From here:

var Twitter = function() {...};

Twitter.prototype = new events.EventEmitter;

But then in "Mastering Node" they do it this way:

function Dog(name) {
  this.name = name;
  EventEmitter.call(this);
}

Dog.prototype.__proto__ = EventEmitter.prototype;

(why would you need to .call it?)

And then in my own code I tried yet another way:

function Class() {}

Class.prototype = EventEmitter.prototype;

They're all just inheriting from EventEmitter in their own way, so wouldn't the simplest solution be the best?


Solution

  • You should use the __proto__ style of inheritance. This assumes you're coding solely for Node, or only supporting your favorite browsers. Also, Base.call(this) is necessary if you care about any logic in the constructor of your base prototype.

    The __proto__ technique to reference a base prototype will ensure that the instanceof operator correctly identifies instances of the prototype. The .constructor property of instances of the child class will reference the constructor you expect it to. It also has the benefit of not instantiating a new instance of the base prototype.

    The new Base() style will also ensure that instanceof gives you the correct answer, but it will run the constructor for Base. Generally not an issue, but can be problematic if your base constructor has required arguments. It will also set the .constructor property to the base constructor, not the descendant constructor.

    Setting the prototype of your class to the prototype of the base class will confuse instanceof as any descendants of the base will also appear to be instances of the child.

    Clear as mud, right? This example should help:

    // Base constructor.
    // A, B, and C will inherit from Base.
    function Base() {
        this.name = 'base';
    }
    
    // new Base() style
    function A() {
        Base.call(this);
    }
    A.prototype = new Base();
    
    // __proto__ = prototype style
    function B() {
        Base.call(this);
    }
    B.prototype.__proto__ = Base.prototype;
    
    // prototype = protoype style
    function C() {
        Base.call(this);
    }
    C.prototype = Base.prototype;
    
    // create instances
    var a = new A();
    var b = new B();
    var c = new C();
    
    // are we who we think we are?
    console.assert(a instanceof A);
    console.assert(b instanceof B);
    console.assert(c instanceof C);
    // so far so good
    
    // do we respect our elders?
    console.assert(a instanceof Base);
    console.assert(b instanceof Base);
    console.assert(c instanceof Base);
    // we have respect
    
    // test to see that Base.call(this)
    // functioned as expected
    console.assert(a.name == 'base');
    console.assert(b.name == 'base');
    console.assert(c.name == 'base');
    // ok, good...
    
    // but now things get weird
    console.assert(a instanceof C);
    console.assert(b instanceof C);
    // that's not right! a is not C, b is not C!
    
    // At least A and B do not confuse identities
    console.assert(!(a instanceof B));
    console.assert(!(b instanceof A));
    
    console.assert(!(c instanceof A));
    console.assert(!(c instanceof B));
    
    // so we've determined that style C is no good.
    // C confuses the inheritance chain.
    
    // B is the winner.
    
    // Why? Only B passes this test
    console.assert(b.constructor == B);
    
    // a and c's constructors actually point to the Base constructor
    console.assert(a.constructor == Base);
    console.assert(c.constructor == Base);
    
    // Word B.