Deep dive into JavaScript Functions and this variable

Ishwar Rimal
6 min readOct 22, 2019

--

NOTE: Most of the concepts and examples in this article are taken from JavaScript: The Good Parts by Douglas Crockford.

In JavaScript, functions are objects, so we can use them as we would use any other datatype. We can store a function into a variable, objects, or an array.

Functions can be passed as arguments to another function. Functions can be returned from a function and so on.

As with any other programming language, functions are created with function literal having its name, parameter, and the body. I assume you already know to create and use it else I advise you not to proceed further.

// example of simple anonymous functionvar add = function ( a, b ) { 
return a + b;
}

The most confusing part of JavaScript to the ones who are new or even an experienced developer is this variable. It might look straightforward at the beginning but using this without understanding its nature can be very dangerous. So let’s dive deep into how the value of this is determined.

This value of this is determined by the so-called invocation pattern, meaning how we invoke the function. There are four ways to do so in JavaScript: the method invocation pattern, the function invocation pattern, the constructor invocation pattern, and the apply invocation pattern.

The Method Invocation Pattern

A function is called a method when it is stored as a property of an object.

// create myObject, it has a value and an increment method.
// the increment method takes an optional parameter.
// if the argument is not a number, then 1 is used as the default.
var myObject = {
value : 0,
increment: function(inc) {
this.value += typeof inc === 'number' ? inc : 1;
console.log(this.value)
}
}
myObject.increment(); // 1
myObject.increment(2); // 3

In the example above, increment function is called a method of myObject. When increment is called, this is bound to the parent object i.e myObject.

When a method of an object is called, the this is bound to the parent object. The method will have access to the vales of object thought the this keyword. The binding of this to the object happens at the time of invocation.

Conclusion: A method will always have access to the context of its object.

The Function Invocation Pattern

Any function which is not a property of an object is invoked as a function.

// calling a function with function invocation patternvar sum = add(1,2) // 3

In a general function invocation, this of function is bound to the global scope. This sometimes gets quite mischievous 😏 and frustrating to understand.

If a function that resides within a parent function is invoked, the inner function is expected to have access to the value of parent functions through this variable but instead this contains the values from the global scope.

This means that a method cannot use the inner function to delegate its work because the function doesn’t share the method’s access to the object as its this is bound to the wrong(global) value.

If in case we want to access the method’s this within the inner function, we have to use a workaround. For it, this value needs to be stored in any reference variable which can be used inside the function. By convention, the name given to the reference variable is that or self.

// Adding new method makeDouble to our existing myObjectmyObject.makeDouble = function(){
var that = this; // assigning this of method to a local variable
var helper = function(){
// we cannot access this here since it will point to the
// global object
that.value = that.value * 2
}
helper()
}
myObject.makeDouble();
console.log(myObject.value) // 6

This example is a continuation of the previous example. Here we are adding a new method called makeDouble to our existing object myObject. This method will double the current value of this.value. To spice things up and to make our understanding of the function invocation pattern clear, we will add a helper function to this method. As the name suggests, this function is going to help the method in making the value double.

As per what we’ve discussed before, this new function cannot access the value of the parent method on its own. So as a workaround, we have assigned the value of this to a local variable that , and using it, we are accessing the value of the method inside the helper function. Let’s not forget to thank Mr. CLOSURE for letting us access the value of an outer function.

Now when we call myObject.makeDouble() in the example above, the helper function gets called from within the method and the value of the method gets updated with double value. Which we can see by printing myObject.value. Since in our previous example we ended up setting value as 3, hence in this example our double value is computed to 6. Please go through both the example once more if this confuses you.

The Constructor Invocation Pattern

JavaScript is a prototypal or prototype-based language and not a classical or class-based language. This means that the object inherits properties directly from another object. We do not need a class to create an object.

Invoking a function with a new prefix will create a new object for us and lead us to the discussion on Constructor Invocation Pattern.

// example of creating new object using functionvar Pokemon = function(name){
this.name = name;
}
var favPokemon = new Pokemon('Pikachu');console.log(typeof(Pokemon)) // "function"
console.log(typeof(favPokemon)) // "object"

The function which is used to create a new object is called as a constructor. By convention the constructor name is capitalized as it might lead to confusion with regular function.

When a new object is created in this manner, this is bound to the new object and the object will also contain a hidden link to the value of the function’s prototype member.

Here is an example…(by Douglas Crockford in his book)

// create a constructor function called Quo.
// It makes an object with a status property
var Quo = function (newStatus) {
this.status = newStatus;
}
// Give all instance of Quo a public method called get_statusQuo.prototype.get_status = function(){
return this.status;
}
// Make an instance of Quo
var myQuo = new Quo('Good status');
console.log(myQuo.get_status()) // Good status

The Apply Invocation Pattern

With all these confusions created around this by the language designer, apply comes for rescue (if used wisely).

With apply, we can specify by ourselves what value we want for this in the function being invoked. It let us choose value for this. The apply method takes two parameters, first is the value that should be bound to this and the second is a list to be passed as a parameter to the function.

// Lets add a public method get_name to our Pokemon constructor
Pokemon.prototype.get_name = function(){
return this.name
}
// Lets call get_name from our previously created favPokemon obj
console.log(favPokemon.get_name()) // Pikachu
// lets create a normal js object with a name property
var firePokemon = { 'name' : 'Charmander' }
// Lets call the get_name method by applying firePokemon obj
console.log(favPokemon.get_name.apply(firePokemon)) // Charmander
// Lets call the same method with null in apply
console.log(favPokemon.get_name.apply(null)) //

As we can see in the example above, when we called get_name with apply, this of get_name changes to the value that is passed as a parameter to apply, hence the name is now changed to the name of a new property of passed object i.e Charmander. Whereas in the second case, when we pass null as a parameter of apply, get_method tries to extract this.name from null, which is not present. Hence it prints nothing.

Hope you found this article useful. I would love to hear your thoughts. 😇

Thanks for reading. 😊

Cheers! 😃

If you find this article useful, you can show your appreciation by clicking on clap button. As the saying goes, ‘When we give cheerfully and accept gratefully, everyone is blessed’.

--

--

Ishwar Rimal
Ishwar Rimal

Written by Ishwar Rimal

Senior FrontEnd Engineer at Intuit. 8 years experience. I write articles on JavaScript, React, Web Optimisation, Startups, Work Life Balance, etc. ❤️ JavaScrip

No responses yet