1

There is a class Car and a class Bot. Bot takes a car object as constructor argument. Also, Car class has setCollisionHandler function which behaves like object.setActionListener(func) in JavaScript. This setCollisionHandler reassigns function onCollision in car object.

Output:

Bot.onCollision: undefined
Bot.myfunc: 23

Expected output:

Bot.onCollision: 23
Bot.myfunc: 23

Why is this happening?

<script>
  class Bot {
    constructor(car) {
      this.x = 23; // some parameter
      this.car = car;
      this.car.setCollisionHandler(this.onCollision);
    }
    myfunc() {
      console.log('Bot.myfunc: ' + this.x); // Bot.myfunc: 23
    }
    onCollision() {
      console.log('Bot.onCollision: ' + this.x); // Bot.onCollision: undefined //why is it undefined??
    }
  }
  class Car {
    onCollision() {
      console.log('Original Car.onCollision'); // never executed as expected
    }
    setCollisionHandler(func) {
      this.onCollision = func;
    }
    updateCarPosition() {
      // more code
      this.onCollision();
      // more code
    }
  }
  car = new Car();
  bot = new Bot(car);
  car.updateCarPosition();
  bot.myfunc();
</script>
treyBake
  • 6,096
  • 5
  • 22
  • 47
rint
  • 225
  • 1
  • 2
  • 10

2 Answers2

1

The reason is because this when called refers to the Car not the Bot as you expect.

It's easy enough to fix by using bind to bind the function back to the instance of the object you expect:

this.car.setCollisionHandler(this.onCollision.bind(this));

<script>
  class Bot {
    constructor(car) {
      this.x = 23; // some parameter
      this.car = car;
      this.car.setCollisionHandler(this.onCollision.bind(this));
    }
    myfunc() {
      console.log('Bot.myfunc: ' + this.x); // Bot.myfunc: 23
    }
    onCollision() {
      console.log('Bot.onCollision: ' + this.x); // Bot.onCollision: undefined //why is it undefined??
    }
  }
  class Car {
    onCollision() {
      console.log('Original Car.onCollision'); // never executed as expected
    }
    setCollisionHandler(func) {
      this.onCollision = func;
    }
    updateCarPosition() {
      // more code
      this.onCollision();
      // more code
    }
  }
  car = new Car();
  bot = new Bot(car);
  car.updateCarPosition();
  bot.myfunc();
</script>

Further reading: How does the "this" keyword work?

Jamiec
  • 118,012
  • 12
  • 125
  • 175
0

That's because when you are calling this.car.setCollisionHandler(this.onCollision); the function are loosing the context. It is pretty common situation in JS

You may do the following here:

this.car.setCollisionHandler(this.onCollision.bind(this));

or

this.car.setCollisionHandler(() => this.onCollision);

RidgeA
  • 1,276
  • 1
  • 8
  • 16