I created a basic emitter and receiver. Please can you let me know why when I console log the receivers messages it returns an empty array?
class Emitter {
constructor(messages = []) {
this.messages = messages;
this.event = () => {};
}
setEvent(fn) {
this.event = fn;
}
trigger() {
this.messages.forEach(message => this.event(message));
}
}
class Reciever {
constructor() {
this.messages = []
}
ping(message) {
console.log(message)
this.messages.push(message)
}
}
const myReciever = new Reciever();
const myEmitter = new Emitter(message = ["A", "B", "C"]);
myEmitter.setEvent(myReciever.ping);
myEmitter.trigger();
console.log(myReciever.messages);
CodePudding user response:
You are losing context on the ping
call:
myEmitter.setEvent(myReciever.ping);
You need to bind it.
myEmitter.setEvent(myReciever.ping.bind(myReciever));
CodePudding user response:
You are storing everything in the emitter, not the receiver. If you print the emitter, the entries are duplicated.
This is because when you pass in the function to the .setEvent(...)
you are using this
which - in this scenario - is referring to the messages from the emitter; it lost the context of the object it belongs to.
Like @MinusFour indicated, you need to bind the function instead.
See demo below
class Emitter {
constructor(messages = []) {
this.messages = messages;
this.event = () => {};
}
setEvent(fn) {
this.event = fn;
}
trigger() {
this.messages.forEach(message => this.event(message));
}
}
class Reciever {
constructor() {
this.messages = []
}
ping(message) {
console.log(message)
this.messages.push(message)
}
}
const myReciever = new Reciever();
const myEmitter = new Emitter(message = ["A", "B", "C"]);
myEmitter.setEvent(myReciever.ping.bind(myReciever));
myEmitter.trigger();
console.log(myReciever.messages);
CodePudding user response:
From the comment above ...
"At the time of
setEvent
the code doesn't care about thethis
context ofmyReciever.ping
. ...ping
gets assigned to an emitters ownevent
just as function, immediately getting oblivious where it originally did belong to."
Besides the already suggested solution of actively bind
ing thisArg
to its method, one also can adapt the code in a way that one can or has to pass to setEvent
a methods's target/context alongside the method/function itself. At trigger
time the method then will be called within this stored context ...
class Emitter {
constructor(messages = []) {
this.messages = messages;
this.handler = () => {};
this.target = null;
}
setEvent(handler, target) {
// `setEvent` might be better renamed to
// `setHandler` or `assignHandler`, etc.
this.handler = handler ?? (() => {});
this.target = target ?? null;
}
trigger() {
this.messages.forEach(message =>
this.handler.call(this.target, message)
);
}
}
class Reciever {
constructor() {
this.messages = []
}
ping(message) {
console.log(message)
this.messages.push(message)
}
}
const myReciever = new Reciever();
const myEmitter = new Emitter(message = ["A", "B", "C"]);
myEmitter.setEvent(myReciever.ping, myReciever);
myEmitter.trigger();
console.log(myReciever.messages);