Node.js – 从EventEmitterinheritance

我在相当多的Node.js库中看到这种模式:

Master.prototype.__proto__ = EventEmitter.prototype; 

(来源于此 )

有人可以给我解释一下,为什么这是一个普遍的模式,什么时候方便?

正如上面代码所说的注释,它将使MasterEventEmitter.prototypeinheritance,所以你可以使用那个“class”的实例来发送和监听事件。

例如,你现在可以这样做:

 masterInstance = new Master(); masterInstance.on('an_event', function () { console.log('an event has happened'); }); // trigger the event masterInstance.emit('an_event'); 

更新 :尽可能多的用户指出,在Node中这样做的“标准”方式是使用“util.inherits”:

 var EventEmitter = require('events').EventEmitter; util.inherits(Master, EventEmitter); 

ES 6样式类的inheritance

这些直接来自文档,但我认为将它们添加到这个受欢迎的问题是不错的。

 const EventEmitter = require('events'); class MyEmitter extends EventEmitter { constructor() { super(); //must call super for "this" to be defined. } } const myEmitter = new MyEmitter(); myEmitter.on('event', () => { console.log('an event occurred!'); }); myEmitter.emit('event'); 

我想git thank谁补充说。 事件发射器 。

注意:文档不会在构造函数中调用super() ,这会导致this不被定义。 看到这个问题 。

要inheritance另一个Javascript对象,特别是Node.js的EventEmitter,但是一般来说,任何对象都需要做两件事情:

  • 为您的对象提供一个构造函数,完全初始化对象; 在你从其他对象inheritance的情况下,你可能想把这个初始化工作委托给超级构造器。
  • 提供一个原型对象,该对象将用作从构造函数创build的对象的[[proto]] ; 在从其他对象inheritance的情况下,您可能希望将其他对象的实例用作原型。

这在Javascript中比在其他语言中更复杂,因为

  • Javascript将对象行为分为“构造函数”和“原型”。 这些概念是为了一起使用,但可以分开使用。
  • Javascript是一种非常可塑的语言,人们对它的使用方式不同,对于“inheritance”的含义没有单一的真正定义。
  • 在很多情况下,你可以避开一些正确的事情,你会发现很多例子可以遵循(包括对这个SO问题的一些其他的答案),这些例子似乎对你的案例很好。

对于Node.js的EventEmitter的具体情况,这是什么工作:

 var EventEmitter = require('events').EventEmitter; var util = require('util'); // Define the constructor for your derived "class" function Master(arg1, arg2) { // call the super constructor to initialize `this` EventEmitter.call(this); // your own initialization of `this` follows here }; // Declare that your class should use EventEmitter as its prototype. // This is roughly equivalent to: Master.prototype = Object.create(EventEmitter.prototype) util.inherits(Master, EventEmitter); 

可能的弱点:

  • 如果您使用为您的子类(Master.prototype)设置原型(无论是否使用util.inherits ,但不要为您的类的实例调用超级构造函数( EventEmitter )),它们将不会被正确初始化。
  • 如果您调用超级构造函数,但不设置原型,EventEmitter方法将无法在您的对象上工作
  • 您可能会尝试使用超类的new EventEmitter实例( new EventEmitter )作为Master.prototype而不是让子类的构造函数Master调用超级构造函数EventEmitter ; 取决于超类构造函数的行为,看起来好像工作正常,但不是相同的事情(并且不能用于EventEmitter)。
  • 您可能会尝试直接使用超级原型( Master.prototype = EventEmitter.prototype ),而不是通过Object.create添加额外的对象层; 这可能看起来像是工作正常,直到有人monkeypatches你的对象Master ,并不经意地monkeypatched EventEmitter和所有其他后代。 每个“class级”应该有自己的原型。

再一次:从EventEmitterinheritance(或者真正的任何现有的对象“类”),你想要定义一个链接到超级构造函数的构造函数,并提供从超级原型派生的原型。

这是原型(原型?)inheritance如何在JavaScript中完成的。 来自MDN :

指的是对象的原型,它可能是一个对象或null(通常意味着对象是Object.prototype,它没有原型)。 有时用它来实现基于原型inheritance的属性查找。

这也适用于:

 var Emitter = function(obj) { this.obj = obj; } // DON'T Emitter.prototype = new require('events').EventEmitter(); Emitter.prototype = Object.create(require('events').EventEmitter.prototype); 

了解JavaScript OOP是我最近在ECMAScript 5的OOP中阅读的最好的文章之一。

我以为这种方法从http://www.bennadel.com/blog/2187-Extending-EventEmitter-To-Create-An-Evented-Cache-In-Node-js.htm是相当整洁:;

 function EventedObject(){ // Super constructor EventEmitter.call( this ); return( this ); } 

道格拉斯·克罗克福德也有一些有趣的inheritance模式: http : //www.crockford.com/javascript/inheritance.html

我发现JavaScript和Node.js中不太需要inheritance。 但是在编写一个应用程序时,inheritance可能会影响可伸缩性,所以我认为性能会受到可维护性的影响。 否则,我只会根据哪个模式导致更好的总体devise,更易于维护,而且不太容易出错。

在jsPerf中testing不同的模式,使用Google Chrome(V8)进行粗略比较。 V8是Node.js和Chrome使用的JavaScript引擎。

这里有一些jsPerfs让你开始:

http://jsperf.com/prototypes-vs-functions/4

http://jsperf.com/inheritance-proto-vs-object-create

http://jsperf.com/inheritance-perf

添加到wprl的响应。 他错过了“原型”部分:

 function EventedObject(){ // Super constructor EventEmitter.call(this); return this; } EventObject.prototype = new EventEmitter(); //<-- you're missing this part