this is an integral concept that is easily stumbled over.
this refers to the the execution context of a function, which gets established at execution time, not definition time.
Functions that take other functions either as arguments, return a function or both are known as higher order functions.
So why do we care that
this gets established at execution time? Because if we take a function and pass it around without being careful, we will experience context loss because the value of
this will change based on where that function finally ends up being invoked. Clear as mud, right? Let’s look at an example:
On line 3 we assign an anonymous function to the property
getBar on the object
foo. When we invoke
getBar in this context on line 8,
getBar is a method of the object
foo, so the implicit value of
this on line 4 is the parent object
foo, and the code produces an unsurprising result: logging the value of
foo.bar which is
Now for the trickiness: line 10 assigns the value of
foo.bar to the variable
qux in the global context, and does so without invoking the anonymous function stored within
foo.bar. When we do invoke the function stored in
qux on line 11, the execution context is now different than it was before, so the implicit execution context here is the global object. In other words,
this now refers to
So why does line 11 log
undefined ? Because we experienced context loss! We tried to log the value of
this.bar, except that in this execution context
this.bar resolves to
global.bar. Because there is currently no
bar property on the
global object, the returned value is
So how to we fix this?
Instead of relying on the implicit execution context, we can decide for ourselves what the execution context should be (i.e. value of
this within the invoked function). We call that explicit execution context. There are several ways we can achieve that.
Here, at invocation time we utilize the the
apply to explicitly set
this to the object
foo when the function executes. It’s a trivial example, but worth noting that we could pass any context here, not just
apply may look to be aliases for one another, they are not. Both methods take the explicit context to be set for their first argument. The difference is that
apply expects its next argument to be an array containing all the other arguments to pass on to the function, while
call expects each argument to be passed individually.
Let’s examine those differences and their limitations before we look at a more permanent solution.
Here we can see that
apply expects an array of arguments that it will pass on to the function that is having its context set, while
call needs each argument to be passed separately. Line 12 logs
NaN (or ‘Not a Number’) because
5 * undefined === NaN. It’s worth noting that when we use both
apply, we are setting the context of
this only for that specific function execution. For a more permanent solution we need to use
By permanently binding the context of
qux on line 10, each invocation of
qux will have its context bound to
foo and will no longer experience context loss. Now take a look at line 6. By passing a second argument to
forEach we can utilize the optional
thisArg argument to similarly set the context of the callback function passed to
forEach. It’s a clunky technique, but I’ll show a better way shortly. In the above example, because the callback function passed to
forEach on line 4 is not a method on the
foo object, it will implicitly execute as a function, not a method. By executing as a function, its implicit value of
this would resolve to the
global object, except that we corrected for that by passing in the
This kind of messiness is why I prefer to use ES6 arrow functions to achieve the same thing with a much cleaner syntax. ES6 arrow functions do not change the context of
this. Also note that as a one-liner, the braces can be omitted. The parenthesis can also be omitted because there is only a single function parameter.
Keep in mind when using
bind that it will only work with a function expression (i.e. a function stored in a variable). It will not work with a function declaration. There are other ways of passing the context of
this into functions nested in methods, such as saving the value of
this into a local variable called something like
self, but that approach is messy and made irrelevant by ES6 arrow functions.
It’s imperative to remember that function execution context a.k.a
this is implicitly determined at invocation time, unless it gets explicitly set beforehand. Function execution context (
this) can be explicitly set for a specific invocation with
apply, or permanently bound by using the