我在很多Node.js库中都看到了这种模式:
Master.prototype.__proto__ = EventEmitter.prototype;
(来源 这里)
有人可以举个例子解释一下为什么这是一个常见的模式,以及在什么情况下它是有用的吗?
我在很多Node.js库中都看到了这种模式:
Master.prototype.__proto__ = EventEmitter.prototype;
(来源 这里)
有人可以举个例子解释一下为什么这是一个常见的模式,以及在什么情况下它是有用的吗?
如代码上方的注释所述,它将使Master
从EventEmitter.prototype
继承,因此您可以使用该“类”的实例来发出和侦听事件。
例如,您现在可以执行以下操作:
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);
第二次更新:随着ES6类的到来,现在建议扩展EventEmitter
类:
const EventEmitter = require('events');
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
myEmitter.on('event', () => {
console.log('an event occurred!');
});
myEmitter.emit('event');
require('events').EventEmitter
-- 我总是忘记。以下是文档链接,以防其他人需要:http://nodejs.org/api/events.html#events_class_events_eventemitter - mikermcneilMasterInstance
应改为 masterInstance
。 - ChrisMaster.prototype = EventEmitter.prototype;
,无需使用 supers。您也可以像这样使用 ES6 扩展(并且在 Node.js 文档的 util.inherits
中鼓励使用):class Master extends EventEmitter
- 您将获得经典的 super()
,但不会将任何内容注入到 Master
中。 - klhNode文档现在建议使用类继承来创建自己的事件发射器:
const EventEmitter = require('events');
class MyEmitter extends EventEmitter {
// Add any custom methods here
}
const myEmitter = new MyEmitter();
myEmitter.on('event', () => {
console.log('an event occurred!');
});
myEmitter.emit('event');
注意:如果在MyEmitter
中定义了一个constructor()
函数,您应该从其中调用super()
以确保也调用了父类的构造函数,除非您有充分的理由不这样做。
super()
,因此Breedly最初的答案(见EDIT历史记录)是完全正确的。在这种情况下,你可以将这个例子复制粘贴到repl中,完全删除构造函数,它仍然可以工作。这是完全有效的语法。 - Aurelio要从另一个Javascript对象(特别是Node.js的EventEmitter,但实际上可以是任何对象)继承,你需要做两件事:
[[proto]]
;在你从其他对象继承时,你可能想使用另一个对象的实例作为你的原型。在Javascript中,这比在其他语言中看起来更加复杂,因为:
对于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);
可能出现的问题:
util.inherits
,但不调用超级构造函数 (EventEmitter
) 来实例化您的类,它们将无法正确初始化。new EventEmitter
) 用作 Master.prototype
,而不是让子类构造函数 Master
调用超级构造函数 EventEmitter
;根据超类构造函数的行为,这似乎可以正常工作一段时间,但不是同一件事情 (对于 EventEmitter 也不起作用)。Master.prototype = EventEmitter.prototype
),而不是通过 Object.create 添加一个额外的对象层次结构;这看起来可能可以正常工作,直到有人猴子补丁您的对象 Master
,无意中也猴子补丁了 EventEmitter
和所有其他后代。每个“类”都应该有自己的原型。再次说明:要从 EventEmitter(或任何现有对象“类”)继承,您需要定义一个链接到超级构造函数的构造函数,并提供一个从超级原型派生的原型。
下面的代码也可以实现这个功能:proto 是指对象的原型,可以是一个对象或 null(通常表示该对象是 Object.prototype,它没有原型)。有时它用于实现基于原型继承的属性查找。
var Emitter = function(obj) {
this.obj = obj;
}
// DON'T Emitter.prototype = new require('events').EventEmitter();
Emitter.prototype = Object.create(require('events').EventEmitter.prototype);
理解JavaScript面向对象编程是我最近在ECMAScript 5中阅读的最好的关于OOP的文章之一。
Y.prototype = new X();
是一种反模式,请使用 Y.prototype = Object.create(X.prototype);
。 - Raynosnew X()
实例化 X.prototype
并调用 X
对其进行初始化。Object.create(X.prototype)
仅仅是实例化一个对象。你不想初始化 Emitter.prototype
。我找不到一个很好的文章来解释这个问题。 - Raynosfunction EventedObject(){
// Super constructor
EventEmitter.call( this );
return( this );
}
emit
和on
都显示为未定义。 - dopatramanreturn(this)
不就是为了链式调用吗? - blablablafunction EventedObject(){
// Super constructor
EventEmitter.call(this);
return this;
}
EventObject.prototype = new EventEmitter(); //<-- you're missing this part
util.inherits
,因为很多聪明人会为你更新这些选项。 - Cool Blue
__proto__
是一种反模式,请使用Master.prototype = Object.create(EventEmitter.prototype);
。 - Raynosutil.inherits(Master, EventEmitter);
。 - thesmartutil.inherits
,推荐的方式是使用ES6类。util.inherits
存在缺陷:https://github.com/nodejs/node/issues/4179 - Andre Pena