
Let’s take a look at one of the quirkiest behaviors in JavaScript. We’ll start by examining the legacy version of the language’s interpretation of the keyword this. Then we’ll consider some new behavior introduced by ES6’s arrow functions. How are they different? Which approach is more intuitive and/or useful? Read on for insight!
Prior to ECMAScript 2015 (a.k.a. ES6), JavaScript used an uncommon approach to the evaluation of this. It made object-orientation in a functional language difficult. For object-oriented design, this serves a critical purpose in creating objects that display polymorphism. The ECMAScript 5.1 specification interprets so-called ThisBinding in a manner often described as confusing and unintuitive.
ThisBinding is one of several execution contexts employed by the JavaScript interpreter to bind values to symbols. When passing functions as callbacks to other functions, the value of this at runtime might surprise you. For example:
|
|
Everything looks like it should work. The announce() method is going to queue up some code for 1.5 seconds in the future. The function it passes to setTimeout refers to some information about the cupcake. These attributes are stored in that instance of the Cupcake object. The helper function _present() is defined in the same scope as the member variables this.type and this.frosting. So why do we get the following output?
|
|
The problem is that when present() eventually goes off, the value of this is not this cupcake instance, even though it really looks like it should be. After all, we’re defining _present() in the same block of code where we set the variables this.type and this.frosting. In truth the value of this is decided later on, in the current execution context in which it was invoked. In the case of _present(), when it’s invoked 1.5 seconds later, we’re actually in the global scope. In that case, this refers to the global object window.
Options for ThisBinding
closure

So how can we make the keyword this resolve to the thing we actually want and not window? To write event-driven, asynchronous code we need our callbacks to know about the context in which they were defined, about the objects involved in the event. If this were just like any other variable, we wouldn’t have anything to worry about. In fact, assigning the value of this to a variable and then using that variable inside the callback provides one possible solution. The closure feature of the language, part of lexical scoping, makes this possible:
|
|
|
|
the bind method
Function.prototype.bind allows us to use a specialized version of the function that bakes in arguments and the this binding. When it’s invoked, the arguments are passed into the function as per usual. Also, the function is called as if it were invoked in the same context as the scope in which it was defined before being passed as a callback. Here’s an example of bind in action:
|
|
|
|
Enter ES6 arrow functions
Since we use anonymous functions so frequently in JavaScript, the new fat arrow functions in the ECMAScript 2015 spec are most welcome. They afford the following advantages:
- concise syntax
- lexical binding of
this - several syntactic sugar features
Let’s take a look at the first two in action:
|
|
And now, the moment you've been waiting for! Presenting...
...a chocolate cupcake with buttercream frosting
Here’s another quick refactor using an arrow function and showing off its implicit return in a concise function body (no curly braces):
|
|
Arrow functions make it easy to inline anonymous functions in all those places we need them, such as asynchronous callbacks, higher order functions and event handlers. this works just like most people would expect. And the best part is, we can still .bind, .call , apply and otherwise use the old ES5 non-arrow functions to our heart’s content in ES6. The specification lets you mix and match both styles, so use whichever suits the situation.
caveats
Some libraries like jQuery and Backbone have their own strategies for this, which use ES5’s interpretation. For example, many jQuery callbacks use $(this) to pinpoint the target object out of the DOM.
|
|
An arrow function would cause the selector above to fail, since the context isn’t what jQuery expects. Backbone, on the other hand, passes around this as an additional parameter throughout its event system. Arrow functions should work fine with the framework and probably make Backbone code more concise:
|
|
Note that arrow functions can be invoked through .call and .apply but we can not pass in this as an argument, only regular variables. Also, arrow functions do not have their own arguments object. Rest parameters still work though. For other quirks and features of arrow functions, see the MDN reference.
Conclusion
I don’t think I’ve ever heard someone say something nice about legacy JavaScript’s specification for this binding. I personally find the behavior counterintuitive but workable. ES5’s notion of the keyword has its own logic and we must understand it. But going forward, the ES6 arrow function gives us another tool, one that delivers a little logical and syntactic sugar for our event-driven, async code.