2016-05-11 5 views
5

EventEmitterを拡張し、finishというイベントをリッスンする2つのオブジェクトのインスタンスがあります。イベントハンドラをコンストラクタの外に設定すると、すべてが期待通りに機能します。各インスタンスは、それがトリガーする、finishの出現を聞きます。しかし、イベントハンドラをコンストラクタ内に設定すると、作成されたインスタンスだけがイベントを聞いて反応します。ここでコンストラクタ内のイベントハンドラは、コンストラクタ外のイベントハンドラとは異なる動作をします

コードは次のとおりです。MyEmitterのコンストラクタ内に設置されているイベントハンドラのバージョンにLISTENER IDは常にそれがそのインスタンスように見える作り、二作成したインスタンスに属していることを

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 

をお知らせ何らかの理由で最初に作成されたインスタンスにそのハンドラがトリガされることはありません。私は私が正しく理解と仮定しています

二つの事実:

  1. thisイベントハンドラでは、常にイベントを発行したオブジェクトである必要があります。
  2. thisはコンストラクタで常に返されるオブジェクトである必要があります(newで呼び出されるため)。

これらの両方が真である場合は、私が他の何かを理解していないとわかりません。

もう1つこれについて私は考えました:イベントは、イベントを発行したのと同じEventEmitterによって常に「聞かれる」べきですか?それは私が思ったことであり、確かにそれが最も一般的な使用事例であるようです。しかし、それが制限ではない場合、たとえば、ボタン上のclickイベントは、他のすべてのボタンのクリックハンドラをトリガしません。

答えて

6

var self = this;を使用して、self変数をEmittersスコープに固定しないことが問題です。 varを残しておくと、JavaScriptはvarと宣言されている一致する変数名が見つかるまで、変数をスコープ内に持ち上げます。あなたが宣言したことは一度もなかったので、selfがグローバルスコープまでホストされ、各エミッタは同じリファレンスで作成されます。

var self = thisを追加すると問題が解決されます。 varを使用せずに変数を宣言することはできないため、use strictを追加して、この種の問題をキャッチすることもできます。

+0

私がそれを見逃していたことがどれほどばかげているのか信じられません。誰かの古いコードでこれを修正しようとしていて、あまりにも深く見えていました。自己の前にvarの不足を完全に逃した。ありがとう! – spectorar

関連する問題