派生 node.js EventEmitter 将在命名对象中调用错误的侦听器 属性
Derived node.js EventEmitter will call the wrong listener when in a named object property
我一直致力于使用一些 node.js 包(Express、mqtt、socket.io)和 MongoDB 数据库和 Angular 运行 在客户端。这个项目是我第一次与任何 JavaScript 合作,所以可以肯定地说我有点菜鸟。
我一直在解决派生 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)
的调用都将执行我为 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
,看起来我采用了正确的方法,所以我有点难过。
感谢阅读以及您能提供的任何帮助!
你的问题变成了这部分代码:
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);
});
});
我一直致力于使用一些 node.js 包(Express、mqtt、socket.io)和 MongoDB 数据库和 Angular 运行 在客户端。这个项目是我第一次与任何 JavaScript 合作,所以可以肯定地说我有点菜鸟。
我一直在解决派生 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)
的调用都将执行我为 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
,看起来我采用了正确的方法,所以我有点难过。
感谢阅读以及您能提供的任何帮助!
你的问题变成了这部分代码:
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);
});
});