A second approach, that is getting increasingly popular if not drownright “hype” by now, relies on an upcoming syntax for instance field initializers. You can find it in many tutorials and guides, including some official guides.
The idea is to replace the shorthand method syntax with an instance field initializer using an arrow function for value, as in this example. You can then skip dedicated construction code.
There are really two benefits to this approach: first, it’s located right at the method declaration’s spot, instead of elsewhere in your code. When I look for the definition of the sayHi() method, it’s right there in my face. It’s also performant, as performant as the explicit-binding-in-constructor way, because it does pretty much the same thing internally, as we’ll see.
In my opinion, it comes with a serious drawback though: the intent is entirely masked, or at least unclear. There’s really nothing here that tells me this syntax was an intentional, binding-related decision. First, if someone reading this code is unaware of binding concerns, that aspect is completely invisible.
Second, I could bet my arm that people will start copy-pasting this syntax for any method declaration, no questions asked, in the best cargo-culting fashion. It’s a bit like how we saw function expressions (var fx = function(…)) overtake function declarations (function fx(…)) everywhere despite that being often perfectly useless and even counter-productive, as it doesn’t benefit from hoisting, for instance.
As I’m sure you can tell, I’m no fan of this approach. Let’s still see an example, for completeness’ sake.
This is a variation on the previous example, and you can see that when running it, the this is indeed correct!
But… why does this syntax fix our binding problem, exactly?
Well, you see, an instance field initializer is nothing but syntactic sugar for that very same code in the constructor, but prefixed with “this.”. It’s literally the same thing.
As the value is an arrow function, it doesn’t redefine its this, so the one it “sees” comes from the closest relevant surrounding scope, which is the constructor. And quite naturally, the this is guaranteed to refer to the instance in the constructor itself! Which is why it’s possible (and quite baffling the first few times you encounter it) to use this inside expressions passed to instance field initializers, to refer to the “current instance.”