Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing an instance method to super with ES6 classes

As I understand things, this is not available inside the constructor before super( ) is called.

Still, when referring to instance methods, we need to prefix the method with this. So how is it possible to pass a instance method to super( )?

e.g. In the Phaser framework, there is a Button class. The constructor takes a callback for the click-event:

Constructor
new Button(game, x, y, key, callback, callbackContext, overFrame, outFrame, downFrame, upFrame)

callback - The function to call when this Button is pressed.
callbackContext - The context in which the callback will be called (usually 'this').

I want my own button class, which I define like this:

class MyButton extends Phaser.Button {
    constructor(game) {
        super(game, game.world.centerX, game.world.centerY, 'buttonImage');
    }

    clickHandler(button, pointer) {
       //handle the clicking
    }
} 

So how will I pass the clickHandler to super?

this.clickHandler gives the error [Build Error] 'this' is not allowed before super() while parsing file: .... and passing just clickHandler gives me a runtime error of Uncaught ReferenceError: clickHandler is not defined.

Any suggestions?

like image 386
Vegar Avatar asked Sep 11 '15 07:09

Vegar


1 Answers

This is a good use-case for ES6 arrow functions, which are bound lexically to this.

Here is a generic example of logging an instance-derived value by proxying the call to the instance method with an arrow function:

(Try it out on an ES6 REPL, or see it compile in babel.)

class A {
  constructor(method) {
    if(method) {
      method()
      return
    }
    this.callback()
  }

  message() {
    return "a"
  }

  callback() {
    console.log(this.message())
  }
}

class B extends A {
  constructor() {
    super(() => this.callback())
  }

  message() { 
    return "b" 
  }

  callback() {
    console.log(this.message())
  }
}

As you can see, doing this allows us to avoid immediately referencing the thisArg of our new instance before our call to super. In your given example this is implemented like this:

class MyButton extends Phaser.Button {
    constructor(game) {
        super(
            game,
            game.world.centerX,
            game.world.centerY,
            'buttonImage',
            () => this.clickHandler()
        );
    }

    clickHandler(button, pointer) {
       //handle the clicking
    }
}
like image 93
sdgluck Avatar answered Sep 22 '22 04:09

sdgluck