2016-06-28 65 views
0

我一直在使用一些node.js包(Express,mqtt,socket.io)創建我自己的家庭自動化中心MongoDB數據庫和Angular在客戶端運行。這個項目是我第一次使用任何JavaScript,因此可以肯定地說我是一個小菜鳥。Derived node.js EventEmitter會在命名對象屬性中調用錯誤的偵聽器

我一直在解決派生的EventEmitter調用錯誤的偵聽器函數時被引用爲命名屬性的問題。下面是一個小例子,將說明此問題:

var EventEmitter = require('events').EventEmitter; 
var debug = require('debug')('test.js'); 
var util = require('util'); 

var TestEmitter = function (initialState, name) { 
    var self = this; 
    EventEmitter.call(self); 
    this.state = initialState; 
    this.name = name; 
    this.setState = function (newState) { 
     self.emit('change', newState, this.state); 
     self.state = newState; 
    }; 
}; 
util.inherits(TestEmitter, EventEmitter); 

var myObj = { 
    ary: [new TestEmitter(false, 'ary1'), new TestEmitter(true, 'ary2')], 
    named: { 
     name1: new TestEmitter(3, 'name1'), 
     name2: new TestEmitter(4, 'name2') 
    } 
}; 

myObj.ary.forEach(function (aryEmitter) { 
    aryEmitter.on('change', function (newState) { 
     debug(aryEmitter.name + ' changed to: ' + newState); 
    }); 
}); 
for (var prop in myObj.named) { 
    var currEmitter = myObj.named[prop]; 
    debug('prop = ' + prop); 
    debug('name = ' + currEmitter.name); 
    currEmitter.on('change', function (newState) { 
     debug(currEmitter.name + ' changed to: ' + newState); 
    }); 
} 

myObj.ary[0].setState(true); 
myObj.ary[1].setState(false); 
myObj.named.name1.setState(4); 
myObj.named.name2.setState(5); 

實質上,TestEmitter是從EventEmitter派生的對象時,其setState方法被調用,將廣播一個事件change

myObj是對四個TestEmitter實例的引用 - 兩個在數組中,兩個在命名屬性中。在創建myObj後,我爲它們的每個change事件註冊了一個偵聽器,該偵聽器僅將調試輸出寫入控制檯,其調用的回調名稱爲TestEmitter

但是,名爲TestEmitter的引用不會以我期望的方式工作。撥打myObj.named.name1.setState(4)以及myObj.named.name2.setState(5)的電話都將執行我爲EventEmittermyObj.named.name2註冊的回叫功能。運行上面的所有內容將產生以下輸出:

test.js prop = name1 +0ms 
test.js name = name1 +5ms 
test.js prop = name2 +0ms 
test.js name = name2 +0ms 
test.js ary1 changed to: true +0ms 
test.js ary2 changed to: false +0ms 
test.js name2 changed to: 4 +0ms 
test.js name2 changed to: 5 +0ms 

任何人都可以提供任何幫助嗎?我已經閱讀了相當多的關於創建衍生EventEmitters的最佳方法,它看起來像我採取正確的方法,所以我有點難住。

感謝您閱讀並提供任何幫助!

+0

你'尋找'綁定'函數https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind或使用'forEach'循環中的箭頭函數 –

回答

0

你的問題就變得在這部分代碼:

for (var prop in myObj.named) { 
    var currEmitter = myObj.named[prop]; 
    debug('prop = ' + prop); 
    debug('name = ' + currEmitter.name); 
    currEmitter.on('change', function (newState) { 
     debug(currEmitter.name + ' changed to: ' + newState); 
    }); 
} 

所以,當一個事件被觸發,該函數處理程序中,currEmitterloop最後一個元素的值。

一個簡單的解決辦法是使用encapsule它的功能,創建一個新的範圍,做的事情在這個函數內:

for (var prop in myObj.named) { 
    var currEmitter = myObj.named[prop]; 
    (function(currEmitter){ 
     currEmitter.on('change', newState=>{ 
     debug(currEmitter.name + ' changed to: ' + newState); 
     }); 
    })(currEmitter); 
} 

或者你可以使用Object.keys()

Object.keys(myObj.named).forEach(function(key){ 
    var currEmitter = myObj.named[key]; 
    currEmitter.on('change', function(newState){ 
    debug(currEmitter.name + ' changed to: ' + newState); 
    }); 
}); 
+0

感謝您的輸入 - - 我肯定需要做一些關於這些箭頭功能的閱讀。但是,即使不知道更多關於它們的信息,我想指出 - myObj.ary.forEach循環中的匿名函數按預期工作。這是'for(var prop in myObj.named)'循環,這是不正確的。 –

+0

你編輯你的答案,所以現在我看起來像一個瘋狂的人:) 你介意幫助我理解'Object.keys(myObj.named).forEach(function(key){})'和'for在myObj.named中的var鍵){}'?爲什麼這些會產生不同的結果? –

+0

'對象。keys()'接受一個函數,這意味着創建一個'新的作用域',該作用域可以被處理器訪問。在'for(var prop in obj)'的情況下,沒有創建範圍。 –

相關問題