The invocation pattern and the context of ‘this’

In this example I’m demonstrating the varying context of ‘this’, which depends on the way we invoke the function containing it.
The changing context of ‘this’ depending on the way of invocation can be a source of a lot of confusion, and it is important that we understand how Javascript applies context to the ‘this’ variable in functions.

In Javascript, the ‘this’ variable is always attached to functions (opposed to other class based languages).
Whenever we invoke a function, ‘this’ is given a certain value, depending on how we invoke it.
This is often called the invocation pattern.
There are four ways to invoke functions in Javascript.
We can invoke the function as a method, as a function, as a constructor, or with apply.

Let’s take a look at the code above to gain a better understanding of how the different invocation methods change the context of a function (of an object) in Javascript.

An unexpected behaviour of the invocation pattern is when we invoke John() as ‘normal’ function, the context of ‘this’ will bound to the global scope (the ‘window’ object). This is can be quite bad, as we unexpectedly pollute the global scope with all the properties and methods defined on John().
To differentiate between ‘normal’ functions and constructor functions, the markup convention is to always capitalize the initials of constructor functions. Although this method can help developers to avoid improper invocation of a constructor, it doesn’t prevent it.
A contested pattern to prevent this from happening is to place the following code in the beginning of the constructor function, in which case if the constructor function is invoked incorrectly (without the ‘new’ keyword) it will still return the constructor invoked correctly:
if (!(this instanceof John)) {
return new John();
}

Another preventive approach is using ‘strict mode’ in our code, which also prevents improper invocation of constructors, as in ‘strict mode’ ‘this’ is undefined during ‘normal’ function calls.

Another unexpected behaviour might be the context of methods which return a closure. Methods that return closures loose the context of the parent object, which can be solved by using apply() where we can explicitly supply the context for the closure, or by passing the context of ‘this’ to another variable within the scope of the closure like so: var that = this;.
ES6’s fat arrow functions are also a solution for this case, as fat arrow functions inherit context directly from their parents, so the context of ‘this’ would be what we expect: the context of the parent object containing the method.

The ‘detachment’ of a method from the parent object makes it easier to understand why closures loose their context:
var f = john.sayName;
f();

In this case we also lost the context of this, but it sort of seems logical why it happens: we are executing the detached method outside the context of the parent object.

Leave a Reply

Your email address will not be published. Required fields are marked *