0

How would I call a method in instanced object, but in context of another instanced object.

Best way to explain is with this brief expamle..

game.js

var ball = new Ball();
ball.addMotionListener(function(){this.color = someNewRandomColor});

inside ball.js

Ball = class{
  constructor(){
    this._position = new Vector(0,0);
    this._color = red;
    this._onChangeManager = new OnChangeManager();
  }

  addMotionListener(listener){
    this._onChnangeManager.addMotionListner(listener);
  }

  set position(newP){ 
    this._position = newP; 
    this._onChangeManager.motionEvent();
  }

}

and in onChangeManager.js

OnChangeManager = class{
  constructor{ this._motionListenerQueue = [] }

  addMotionListener(newListener){
    this._motionListenerQueue.push(newListener);
  }

  motionEvent(){
    for(listener in _motionListenerQueue){
      listener();
    }
  }
}

Now in game.js

kickBall(ball);

which changes ball position, triggers motion event listener in onChangeManager, with goal of changing balls color. Ofcourse this doesn't work, since this.color is in ball's context and not in onChangeManager's.

Is it possible to run method in onChangeManager object, but in ball's context?

Edit: Sorry for trivial/duplicate question, I am not familiar with js contexts

Bhargav Rao
  • 50,140
  • 28
  • 121
  • 140
Jonzi
  • 141
  • 1
  • 2
  • 13
  • 1
    Possible duplicate of [How to access the correct \`this\` inside a callback?](https://stackoverflow.com/questions/20279484/how-to-access-the-correct-this-inside-a-callback) – Jared Smith Jan 09 '19 at 15:46
  • [Function.prototype.bind](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Function/bind) – Jared Smith Jan 09 '19 at 15:46
  • You can use `call()` and something like: `this._onChnangeManager.addMotionListner.call(this, listener);` to set this for the function call. – Mark Jan 09 '19 at 15:48
  • too-long names like `_onChnangeManager` are good places for typos to hide – Mulan Jan 09 '19 at 15:52
  • so every object that can interact with the "changeManager" needs its own `addMotionListener` method? – Mulan Jan 09 '19 at 15:54
  • `for(listener in _motionListenerQueue){ listener() }` check out the difference between [for..in](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in) and [for..of](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of). you want the latter here – Thomas Jan 10 '19 at 11:11
  • @Thomas Hey, that was just pseudocode, I wasn't careful with syntax – Jonzi Jan 10 '19 at 17:51

1 Answers1

2

You can bind the context to the function that is being passed as a callback using Function.prototype.bind:

var ball = new Ball();
ball.addMotionListener(function() {
    this.color = someNewRandomColor
}.bind(ball));

P.S. In the callback you are referring to color property, while in Ball constructor there is _color property. I'm not sure if this difference is intended.

antonku
  • 7,377
  • 2
  • 15
  • 21
  • Is it possible to set whole onChangeManager to be bound to ball on `new OnChangeListener` ? Im sure your solution would work, but would take me whole day to fix in my project :s – Jonzi Jan 09 '19 at 15:55
  • Well, you can pass the `Ball` instance in `OnChangeManager` like: `this._onChangeManager = new OnChangeManager(this);` and then in `OnChangeManager` constructor assign it to a property, let's say `this.ball`. Then in `for` loop you can invoke each listener using `Function.prototype.call` with `this.ball` as a context: `listener.call(this.ball)`; – antonku Jan 09 '19 at 16:02
  • Thanks that exactly what I needed, Thanks :) – Jonzi Jan 09 '19 at 16:13
  • @Jonzi My pleasure :) – antonku Jan 09 '19 at 16:16