Search code examples
javascriptclassmethodsthisinstance

Why does my receiver's class instance method not receive any data?


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);


Solution

  • From the comment above ...

    "At the time of setEvent the code doesn't care about the this context of myReciever.ping. ... ping gets assigned to an emitters own event just as function, immediately getting oblivious where it originally did belong to."

    Besides the already suggested solution of actively binding 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);