开发者

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 d开发者_如何学Goo 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?


Node has a library function, util.inherits, that is slightly more straightforward than the accepted answer. Code below is modified from the v0.8.12 docs.

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

function MyStream() {
  events.EventEmitter.call(this);
}

util.inherits(MyStream, events.EventEmitter);


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.
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜