我一直在玩EventEmitter,但我对如何从模块实现它感到困惑。我见过几种不同的方式,它们似乎都有效。以下是我见过的一些内容:
来自here:
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继承,所以最简单的解决方案不是最好的吗?
答案 0 :(得分:20)
Node有一个库函数util.inherits,它比接受的答案稍微简单一些。以下代码是从v0.8.12 docs修改的。
var util = require("util");
var events = require("events");
function MyStream() {
events.EventEmitter.call(this);
}
util.inherits(MyStream, events.EventEmitter);
答案 1 :(得分:18)
您应该使用__proto__
继承方式。 This assumes you're coding solely for Node, or only supporting your favorite browsers。此外,如果您关心基础原型的构造函数中的任何逻辑,则Base.call(this)
是必需的。
引用基础原型的__proto__
技术将确保instanceof
运算符正确识别原型的实例。子类的实例的.constructor
属性将引用您期望它的构造函数。它还具有不实例化基本原型的新实例的好处。
new Base()
样式还将确保instanceof
为您提供正确答案,但它将运行Base的构造函数。通常不是问题,但如果您的基础构造函数具有必需参数,则可能会出现问题。它还会将.constructor
属性设置为基础构造函数not the descendant 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.