I have been stuck on this issue for two days and no dice on other stack overflow posts. I could really use some help.
My goal is to create an event emitter that allows three functions. Subscribe, Unsubscribe, and Emit - where emit sends the passed arguments to all subscription functions.
The problem that I am running into is that I can't seem to pass just a function into the subscription. I have to pass an anonymous function in that calls the other function.
subscribe(() => entities[1].eventEmitter.emit())
vs subscribe(entities[1].eventEmitter.emit)
. I don't seem to understand what the actual difference here is, and why they would reference different 'this' values. I thought the second example is a simplified version of the first? Anyone have an explanation on why the two versions reference different 'this' values?
Well, this is all fine and dandy as passing in an anonymous function works, but when I try to unsubscribe, I no longer have a reference to the anonymous function and therefore cannot remove it from the array. I know you could store the anonymous function in a variable, but that is not feasible because I an dynamically generating these Entities and there could be "infinite" entities. I.e. unknown size.
So I must be doing something wrong here. Either I am doing this very wrong and there is a much easier solution out there, or I am just missing something that could solve my problem. Welcome solutions could be a different solution altogether or a way to subscribe, unsubscribe, and emit successfully. Thank you! Please let me know if I can provide additional clarification.
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>