Using jQuery $(this) with ES6 Arrow Functions (lexical this binding)

JRodl3r picture JRodl3r · Dec 27, 2014 · Viewed 56.8k times · Source

Using ES6 arrow functions with lexical this binding is great.

However, I ran into an issue a moment ago using it with a typical jQuery click binding:

class Game {
  foo() {
    self = this;
    this._pads.on('click', function() {
      if (self.go) { $(this).addClass('active'); }
    });
  }
}

Using an arrow function instead:

class Game {
  foo() {
    this._pads.on('click', () => {
      if (this.go) { $(this).addClass('active'); }
    });
  }
}

And then $(this) gets converted to ES5 (self = this) type closure.

Is a way to have Traceur ignore "$(this)" for lexical binding?

Answer

meagar picture meagar · Dec 27, 2014

This has nothing to do with Traceur and turning something off, this is simply how ES6 works. It's the specific functionality you're asking for by using => instead of function () { }.

If you want to write ES6, you need to write ES6 all the time, you can't switch in and out of it on certain lines of code, and you definitely cannot suppress or alter the way => works. Even if you could, you would just wind up with some bizarre version of JavaScript that only you understand and which would never work correctly outside of your customized Traceur, which definitely isn't the point of Traceur.

The way to solve this particular problem is not to use this to gain access to the clicked element, but instead use event.currentTarget:

Class Game {
  foo(){
    this._pads.on('click', (event) => {
      if(this.go) {
        $(event.currentTarget).addClass('active');
      }
    });
  }
}

jQuery provides event.currentTarget specifically because, even before ES6, it is not always possible for jQuery to impose a this on the callback function (ie, if it was bound to another context via bind.