javascript - JavaScript 中的高阶函数并在 EventEmitter 的类中引用“this”关键字
问题描述
我已经在这个问题上停留了两天,并且在其他堆栈溢出帖子上没有骰子。我真的可以使用一些帮助。
我的目标是创建一个允许三个功能的事件发射器。订阅、取消订阅和 Emit - 其中,emit 将传递的参数发送到所有订阅函数。
我遇到的问题是我似乎无法将一个函数传递给订阅。我必须传递一个匿名函数来调用另一个函数。
subscribe(() => entities[1].eventEmitter.emit())
与subscribe(entities[1].eventEmitter.emit)
。我似乎不明白这里的实际区别是什么,以及为什么他们会引用不同的“this”值。我认为第二个示例是第一个示例的简化版本?任何人都可以解释为什么两个版本引用不同的“this”值?
好吧,这一切都很好,因为传入匿名函数可以工作,但是当我尝试取消订阅时,我不再有对匿名函数的引用,因此无法将其从数组中删除。我知道您可以将匿名函数存储在变量中,但这不可行,因为我动态生成这些实体并且可能存在“无限”实体。即未知大小。
所以我一定在这里做错了什么。要么我做错了,那里有一个更简单的解决方案,要么我只是错过了一些可以解决我的问题的东西。Welcome 解决方案可以是完全不同的解决方案,也可以是成功订阅、取消订阅和发出的一种方式。谢谢!如果我能提供额外的说明,请告诉我。
class EventEmitter {
constructor() {
this.subscriptions = [];
}
subscribe(fn) {
this.subscriptions.push(fn);
}
unsubscribe(fn) {
this.subscriptions = this.subscriptions.filter(subscription => subscription !== fn);
}
emit(args) {
// upon subscribing, you should get an error when doing trigger that amounts to
// "message": "Uncaught TypeError: Cannot read property 'subscriptions' of undefined"
// this happens because the line entities[0].eventEmitter.subscribe(entities[1].eventEmitter.emit);
// with argument passed in entities[1].eventEmitter.emit refers to the window?
// so this.subscriptions is not defined
// console.log(this);
console.log('emitting');
this.subscriptions.forEach(subscription => subscription(args));
}
}
class Entity {
constructor() {
this.eventEmitter = new EventEmitter();
}
}
const entities = [
new Entity(),
new Entity(),
];
document.getElementById('add').addEventListener('click', () => {
// works, but requires an anonymous function that can't be removed
entities[0].eventEmitter.subscribe(() => entities[1].eventEmitter.emit());
// doesn't work because 'this' in the emit funciton refers to the window
entities[0].eventEmitter.subscribe(entities[1].eventEmitter.emit);
}, false);
document.getElementById('trigger').addEventListener('click', () => {
entities[0].eventEmitter.emit();
}, false);
document.getElementById('remove').addEventListener('click', () => {
// how? ...
// entities[0].eventEmitter.unsubscribe(entities[1].eventEmitter.emit);
}, false);
<button id='add'>add event listener</button>
<button id='trigger'>trigger emit on element 0</button>
<button id='remove'>remove event listener</button>
解决方案
嗯,您可以做的是使用.bind()
并将其绑定到您的事件发射器类
我创建了一个存储方法的数组。
class EventEmitter {
constructor() {
this.subscriptions = [];
}
subscribe(fn) {
this.subscriptions.push(fn);
}
unsubscribe(fn) {
this.subscriptions = this.subscriptions.filter(subscription => subscription !== fn);
}
emit(args) {
// upon subscribing, you should get an error when doing trigger that amounts to
// "message": "Uncaught TypeError: Cannot read property 'subscriptions' of undefined"
// this happens because the line entities[0].eventEmitter.subscribe(entities[1].eventEmitter.emit);
// with argument passed in entities[1].eventEmitter.emit refers to the window?
// so this.subscriptions is not defined
// console.log(this);
this.subscriptions.forEach(subscription => {
console.log("emit");
subscription(args)
});
}
}
class Entity {
constructor() {
this.eventEmitter = new EventEmitter();
}
}
const entities = [
new Entity(),
new Entity(),
];
let methods = [];
document.getElementById('add').addEventListener('click', () => {
let method = entities[1].eventEmitter.emit.bind(entities[1].eventEmitter)
methods.push(method);
entities[0].eventEmitter.subscribe(method);
}, false);
document.getElementById('trigger').addEventListener('click', () => {
entities[0].eventEmitter.emit();
}, false);
document.getElementById('remove').addEventListener('click', () => {
entities[0].eventEmitter.unsubscribe(methods.pop())
}, false);
<button id='add'>add event listener</button>
<button id='trigger'>trigger emit on element 0</button>
<button id='remove'>remove event listener</button>
推荐阅读
- css - 如何在 Bootstrap 的背景图像中添加文本?
- c# - 从分钟转换为毫秒,然后转换为 Int
- c# - 用户设置中保存的列表错误:字符串未保存
- javascript - 可以在 Express.js 中伪造 req.ip 吗?
- android - 透明图像背景问题android
- selenium - 启动 Internet Explorer 时出现意外错误。IELaunchURL() 使用 Selenium 3.13.0 返回 HRESULT 80070012:IEDriverServer_x64_3.13.0
- android - SQL with between in 2 columns 语句
- java - LocalDateTime isAfter 和 isBefore 配置时间
- php - 显示已登录的用户详细信息
- reactjs - 将 react-router 路由分解为自己的文件