Node.js – 从EventEmitterinheritance
我在相当多的Node.js库中看到这种模式:
Master.prototype.__proto__ = EventEmitter.prototype;
(来源于此 )
有人可以给我解释一下,为什么这是一个普遍的模式,什么时候方便?
正如上面代码所说的注释,它将使Master
从EventEmitter.prototype
inheritance,所以你可以使用那个“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
,并不经意地monkeypatchedEventEmitter
和所有其他后代。 每个“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中阅读的最好的文章之一。
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
添加到wprl的响应。 他错过了“原型”部分:
function EventedObject(){ // Super constructor EventEmitter.call(this); return this; } EventObject.prototype = new EventEmitter(); //<-- you're missing this part