我有两个扩展EventEmitter
的对象实例并侦听名为finish
的事件。如果我在构造函数外部设置事件处理程序,一切都按预期工作。每个实例都会听到它触发的finish
的出现。但是如果我在构造函数中设置事件处理程序,则只有第二个创建的实例会听到并对事件作出反应,或者看起来如此。
以下是代码:
var util = require('util');
var EventEmitter = require('events').EventEmitter;
var fs = require('fs');
var NEXT_ID = 0;
var MyEmitter = function() {
EventEmitter.call(this);
this.id = NEXT_ID;
NEXT_ID++;
console.log('CREATED EMITTER WITH ID:', this.id)
self = this;
this.on('finish', function() {
console.log('FINISH EVENT . CONSTRUCTOR LISTENER .',
'LISTENER ID:', self.id,
'. ORIGINATOR ID:', this.id);
});
};
util.inherits(MyEmitter, EventEmitter);
var setFinishListener = function(emitter) {
emitter.on('finish', function() {
console.log('FINISH EVENT . NON-CONSTRUCTOR LISTENER .',
'LISTENER ID:', emitter.id,
'. ORIGINATOR ID:', this.id);
});
}
var emitter0 = new MyEmitter();
var emitter1 = new MyEmitter();
setFinishListener(emitter0);
setFinishListener(emitter1);
emitter0.emit('finish');
emitter1.emit('finish');
// The following is logged to the console:
// FINISH EVENT . CONSTRUCTOR LISTENER . LISTENER ID: 1 . ORIGINATOR ID: 0
// FINISH EVENT . NON-CONSTRUCTOR LISTENER . LISTENER ID: 0 . ORIGINATOR ID: 0
// FINISH EVENT . CONSTRUCTOR LISTENER . LISTENER ID: 1 . ORIGINATOR ID: 1
// FINISH EVENT . NON-CONSTRUCTOR LISTENER . LISTENER ID: 1 . ORIGINATOR ID: 1
请注意,在LISTENER ID
的构造函数中设置的事件处理程序版本的MyEmitter
始终属于第二个创建的实例,使得该实例似乎始终捕获事件首先,由于某种原因,第一个创建的实例永远不会触发该处理程序。
我假设我理解正确的两个事实:
this
应始终是发出事件的对象。this
应该始终是构造函数返回的对象(因为它是使用new
调用的)。如果这些都是真的,我不知道还有什么我不理解会导致表现出来的行为。
这让我想到的另一件事是:事件总是被发出事件的同一个EventEmitter“听到”吗?这就是我的想法,当然这似乎是最常见的用例。但是,如果这不是限制,那么例如按钮上的click
事件如何不触发所有其他按钮的点击处理程序?
答案 0 :(得分:6)
问题是您没有使用var self = this;
将self
变量固定到发射器范围。当你离开var
时,Javascript会在范围内提升变量,直到找到用var
声明的匹配变量名。由于您从未声明过,self
将一直托管到全局范围,因此每个发射器都将使用相同的引用创建。
添加var self = this
将解决问题。您还可以添加use strict
来捕获这些类型的问题,因为它不允许您在不使用var
的情况下声明变量。