5

我一直在玩EventEmitter,但我对我应该如何从模块中实现它感到困惑。我见过几种不同的方法,它们似乎都有效。以下是我见过的一些:

这里

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

Twitter.prototype = new events.EventEmitter;

但是在“Mastering Node”中,他们这样做了:

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

Dog.prototype.__proto__ = EventEmitter.prototype;

(为什么需要 .call 呢?)

然后在我自己的代码中,我尝试了另一种方式:

function Class() {}

Class.prototype = EventEmitter.prototype;

他们都只是以自己的方式从 EventEmitter 继承,那么最简单的解决方案不是最好的吗?

4

2 回答 2

20

Node 有一个库函数 util.inherits,它比公认的答案稍微简单一些。下面的代码是从v0.8.12 文档修改而来的。

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

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

util.inherits(MyStream, events.EventEmitter);
于 2012-10-14T02:35:03.457 回答
18

你应该使用__proto__继承的风格。这假设您只为 Node 编写代码,或者只支持您最喜欢的浏览器。此外,Base.call(this)如果您关心基本原型的构造函数中的任何逻辑,则这是必要的。

引用基本原型的__proto__技术将确保instanceof操作员正确识别原型的实例。.constructor实例的属性将引用您期望的构造函数。它还具有不实例化基本原型的新实例的好处。

new Base()样式还将确保instanceof为您提供正确的答案,但它将运行 Base 的构造函数。通常不是问题,但如果您的基本构造函数具有必需的参数,则可能会出现问题。它还将.constructor属性设置为基本构造函数,而不是后代构造函数

的原型设置为基的原型会造成混淆instanceof,因为基类的任何后代也似乎是子类的实例。

像泥一样清澈,对吧?这个例子应该有帮助:

// 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.
于 2011-08-02T03:50:07.093 回答