Revealing the Mystery Behind This in Javascript

A lot of developers scratch their heads when it comes to this in javascript. One of the main reasons is that this in javascript is different compared to other languages like in Java or self in python.

this points to an object and its value depends on how the function is invoked. So what are the different ways to invoke a function? And how do we use this information to conclude which object would this resolve to? In this post, we’ll reveal the mystery behind this in javascript using various examples. Since I’m deep into music, my examples have several singers 🎤 and their songs 🎵 in them. So let’s get started.

Function invocation, context (this) and scope

Before going ahead, let’s understand a few terminologies

  1. Function invocation – it is simply calling a function and executing the code inside it
  2. Context – Content is the value of this inside a function
  3. Scope – Scope refers to the variables that it can access. Functions have access to the variables declared inside of them and outside of them but not to those variables that are in functions nested inside them

Some people think that scope and context are the same. Let’s understand the difference with an example. 

call() is used to override the value of this. We’ll learn more about this in indirect invocation. As we can see, this.name resolves to undefined so the variable name is present in the scope of the function and not its context(value of this).

On a side note, if you haven’t heard Blank Space, you live under a rock 🪨. I would advise you to go and listen to it, right this instant.

Global scope

In the global scope, this points to the global object. In web browsers the global object is window.

💡 ES2020 introduced globalThis object that gives us access to the global object in various environments. So, if you are writing javascript code for different environments, instead of using different syntaxes like window, global etc, you can use globalThis to access the global environment.

Some global objects are given below

EnvironmentGlobal
Web Browserswindow
Web Workersself
Node.jsglobal
global objects in different environments

If you initialize a variable in global scope, js will add this variable to the global object. The same applies to function as well.

Different ways of function invocation

1. Function invocation

this points to the global object in function invocation. As seen above the global object is different for different environments, so is the value of this in javascript.

What about nested functions?

As we can see, this points to the window object for nested functions as well.

this in strict mode

this is undefined in strict mode for function invocation.

Also read about some common interview questions on closures

2. Method invocation

this in method invocation points to the object, the method is in. Let’s understand this with an example

Here we have a singer object which contains a property name and a function song which logs this.name. Since this points to singer object and singer has a property name, this.name is Dua Lipa.

Another point to note here is that this behavior is not affected by how the function is defined. In the above example, the function was placed inside the object but what if we do this.

What about functions nested in an object which is further inside another object 

Another most common mistake done by developers is when a function is nested inside another function which is a part of an object.

What’s the output of the below code snippet? Let’s see if you can get this right

window you say? Bravo! 

this will point to the global object because as I had mentioned at the start of the article, the value of this depends on how the function is invoked. Since in the example above songAndSinger is a function invocation and in the case of a function invocation, this points to the global object.

But how do we make this point to singer object in this case? A simple approach would be to store the value of this in a variable and use it inside songAndSinger function. 

We also have other ways to change the context of a function. We will revisit this example when we discuss Indirect invocations.

3. Constructors

When new keyword is followed by the function name, the invocation becomes a constructor invocation. This creates an instance of the function.

What happens on a constructor invocation of a function

  1. An empty object is created and the constructor property of the object is set to the function
  2. The prototype of the function is linked to the newly created object
  3. Then, the function is called and this value is set to the newly created object
  4. This newly created object is returned
constructor invocation (this in javascript)
constructor invocation

__proto__ in an object points to the prototype property of the object it was created from. As explained above, we can see here that the constructor property of singer1 is set to Singer function and the prototype of the Singer function is linked to singer1.

Now let’s look at a common mistake developers tend to do.
What happens when you invoke the function without the new keyword?

This becomes a function invocation. Since the function does not return anything, singer2 is undefined and hence throws an error.

How do we avoid this mistake?

We can add a condition in the function that checks if the instance of this is the function. If not, we throw an error.

ES6 introduced a property called new.target that allows you to check whether an invocation is function or constructor.

4. Indirect invocation

What if we want to force a function to use a different value of this in javascript?

We have 2 methods for this purpose – call() and apply()

The first argument to call is the value of this, followed by the arguments to the function func.call(thisArg, arg1, arg2….). On the other hand first argument to apply is the value of this, followed by an array of arguments passed to the function func.apply(thisArg, [arg1, arg2….])

Hard binding

We can force a function to have the same context(or the value of this) no matter how or from where it’s called.

taylorSwift() is a function invocation, so the value of this is the window object.
taylorSwift.call(singer2) is an indirect invocation, therefore the value of this is {name: ‘Selena Gomez’}. But since singerName is being called with singer1, Taylor Swift is logged to the console.

Let’s revisit the example that we discussed in method invocation

In this example we wanted songAndSinger to use the value of singer as its context. Can we do it using call and apply? Absolutely

5. Bind

bind function is a powerful method that creates a new function with the same body, scope but with a different context(value of this).

Applications of bind

1. Callbacks

When a function is passed as a callback, it losses its value of this.

Let me simplify this, the above code can be written as

song.getSong and song1 are passed as a callback to setTimeout function. this inside the setTimout function points to the global object, since there’s no songNamevariable in the global object, it outputs undefined.

We can solve this problem using bind()

2. Function borrowing

bind allows us to borrow a function from another method without duplicating that method and also overrides the value of this.

bind has a permanent value of this that cannot be changed using call, apply or even bind itself.

To sum it up…

Yes, I’m a huge fan of Taylor Swift 💁‍♀️. All the swifties out there, ping me your favorite album 💿.
Okay now back to our topic. I hope this post helped you clear all your confusion about this in javascript. If you have an interesting example of this keyword, comment in the comment section below.

1 thought on “Revealing the Mystery Behind This in Javascript”

  1. Greetings from Los angeles! I’m bored to death at work so I decided to check out your site on my iphone during lunch break. I really like the info you present here and can’t wait to take a look when I get home. I’m surprised at how quick your blog loaded on my phone .. I’m not even using WIFI, just 3G .. Anyhow, excellent site!

    Reply

Leave a Comment