构造函数中的事件处理程序与构造函数之外的事件处理程序的行为不同

spe*_*rar 5 javascript events node.js

我有一个对象的两个实例,它扩展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
Run Code Online (Sandbox Code Playgroud)

请注意,在LISTENER ID构造函数中设置的事件处理程序的版本MyEmitter始终属于第二个创建的实例,使得该实例似乎始终首先捕获事件,并且由于某种原因,第一个创建的实例从未具有该实例处理程序触发

我假设我理解正确的两个事实:

  1. this 在事件处理程序中应始终是发出事件的对象.
  2. this在构造函数中应该始终是构造函数返回的对象(因为它被调用new).

如果这两个都是真的,我不知道还有什么我不理解导致表现出来的行为.

另一件事让我想到:事件总是被发出事件的同一个EventEmitter"听到"吗?这就是我的想法,当然这似乎是最常见的用例.但是,如果这不是限制,那么例如click按钮上的事件如何不触发所有其他按钮的点击处理程序?

Mik*_*uto 6

问题是您没有使用var self = this;self变量固定到发射器范围.当你离开var时,Javascript会将变量提升到范围内,直到它找到声明的匹配变量名var.由于您从未声明过,因此self将一直托管到全局范围,因此每个发射器都将使用相同的引用创建.

添加var self = this将解决问题.您还可以添加use strict以捕获这些类型的问题,因为它不允许您在不使用的情况下声明变量var.