我一直在使用一些带有MongoDB数据库和Angular在客户端运行的node.js软件包(Express,mqtt,socket.io)创建自己的家庭自动化中心。这个项目是我第一次使用任何JavaScript,所以说我有点像菜鸟是安全的。
我一直在解决派生的EventEmitters在被引用为命名属性时调用错误的侦听器函数的问题。这是一个证明问题的最小例子:
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
派生的对象,它会在调用change
方法时广播setState
事件。
myObj
是对四个TestEmitter
实例的引用 - 数组中有两个,命名属性中有两个。在创建myObj
之后,我为每个change
事件注册了一个监听器,它只是将调试输出写入控制台,其中包含调用其回调的TestEmitter
实例的名称。
但是,指定的TestEmitter
引用并不像我期望的那样工作。对myObj.named.name1.setState(4)
和myObj.named.name2.setState(5)
的调用都将执行我为EventEmitter
myObj.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 :(得分: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);
});
}
因此,当事件被触发时,在函数处理程序内,currEmitter
具有loop
的最后一个元素的值。
一个简单的解决方法是在函数中使用封装,创建新范围,并在此函数中执行操作:
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);
});
});