side-note: Most of my JS experience is writing userscripts for myself, so I definitely do my share of 'this' shenanigans.
Take the following example, which is a normal class method:
> alertSum() { alert(this.a + this.b); }
And here we have an arrow function used to create an instance method (just an arrow function assigned to a property on the instance):
> alertSum = () => { alert(this.a + this.b); }
Then let's say we want to pass the method directly as callback:
> this.button.addEventListener('click', this.alertSum)
The first example (class method syntax) won't have the necessary `this` context unless it has its context bound to the instance through `Function.prototype.bind`. There are other patterns to avoid this (e.g. wrapping all callbacks in arrow functions when passing them), but it's useful to consider that classes methods can easily create confusion because that's _exactly where_ someone more used to a different language may assume the `this` context is bound lexically.
Edit: I was confused about how this could work, so I dug through [1] for a bit. It appears that for each object of that class created, an arrow function will be created on that object and its this will indeed be bound to the same scope that the constructor function is bound to. This is really cleaver and I applaud whoever thought it up!
It is interesting to note that this creates a new arrow function on each object as opposed to the normal definitions which create a single function which is stored in the prototype of the class. (its easier to check this in a browser's dev console then it is to decode the spec)
This would suggest that one should use different approaches for different types of objects: It makes sense to use arrow functions for "resource" or "actor" objects, of which there are few but they may have callback functions. It makes sense to use normal method definitions for "plain old data", of which there may be many, (which would make the arrow functions too expensive) but they should not have callback functions.
Not really. It's contortionist and wasteful and one of the many reasons why mainstream web apps are one big celebration of bloat on a boat.
The neophyte programmers who have turned into expert Modern JS programmers are always recommending arrow functions like this because they've never actually looked at the event listener interface. What happens is they try to make things more complicated than they need to be and bodge their event registration. So they apply a "fix" by doing what they do with everything else: layering on even more. "What we need," they say, "are arrow functions."
No.
Go the other way. Approach it more sensibly. You'll end up with a fix that is shorter than the answer that the cargo cult NPM/GitHub/Twitter programmers give. It's familiar to anyone coming from a world with interfaces as a language-level construct and therefore knows to go look at the interface definition of the interface that you're trying to implement.
Make your line for registering an event listener look like this: `this.button.addEventListener("click", this)`, and change the name of your `addSum` method to `handleEvent`. (Read it aloud. The object that we're dealing with (`this`) is something that we need to be able to respond to clicks, so we have it listen for them. Gee, what a concept.) In other words, the real fix is to make sure that the thing we're passing in to `addEventListener` is... actually an event listener.
This goes over 90% of frontend developers' heads (and even showing them this leads to them crying foul in some way; I've seen them try to BS their way through the embarrassment before) because most of the codebases they learned from were written by other people who, like themselves, only barely knew what they were doing. Get enough people taking this monkey-see-monkey-do approach, and from there you get "idioms" and "best practices" (no matter whether they were even "good" in the first place, let alone best).