'this' in javascript - Part One

'this' in javascript - Part One

A detailed explanation of 'this' concept in Javascript

ยท

5 min read

Hello everyone, we're going to learn about this in Javascript in this article. To be honest, this topic kept me in confusion for a very long time because of the reason how Javascript works. From an interview perspective, it becomes necessary to know all the gotchas and misconceptions around the topic because it is asked a lot. Basic knowledge of the language is required to understand this article.

I will publish this article in two parts because reading everything together will be confusing and overwhelming for the readers. In the first part of the blog, we're going to cover two cases while evaluating this in a Javascript program, with that in mind let's get started ๐Ÿš€

okay, what is 'this'?

In simple words, this is the context or the binding that is made when the function is invoked. If I go into details, what this refers to entirely depends on how the function is invoked and where the function is called. There are certain rules which you have to follow in order to determine this in a program, we will look at how the binding affects the value of this.

1. Function Invocation (Default binding)

this always refers to the global object in a regular function call

Read the above line thrice because it is going to come in handy later in the article. Let's see the above rule in action.

// default binding
function foo() {
  console.log(this === window)   // => true
}

foo();   // call-site
 /* foo() is called as a standalone function
    Therefore, this in foo() is a global object
 */

We should not forget how var, let and const behave in a program. Every variable declaration done at the global level automatically becomes the property on the window object.

  • Only declaring variables with var add them to the window object.
  • Variables declared using let and const are not added to the window object.
var myDog = "proton"
function sayDogName() {
  console.log(this.myDog) // => proton
}
sayDogName();

const myCat = "arya";
function sayCatName() {
  console.log(this.myCat) // => undefined
}
sayCatName();
// using let will also give "undefined"

"strict" mode

this is undefined in strict mode for the default binding

function foo() {
  "use strict";
   console.log(this === undefined);  // => true
}

foo();

2. Method Invocation (Implicit Binding)

To start with, a method is simply a function stored in an object's property. A method invocation will look like - foo.bar() or foo['bar'](). Remember the difference between method invocation and function invocation.

this refers to the object that owns the method in method invocation.

Now, let's see some code

const favoriteMovie = {
  name: "The Matrix",
  sayName() {
    console.log(this === favoriteMovie) /* => true */
    console.log(this.name)  /* => The Matrix  */ 
  }
}

favoriteMovie.sayName();

const superhero = {
  name: "batman",
  show() {
    console.log(this.name) /* => batman  */
  },
  rival: {
    name: "superman",
    show() {
      console.log(this.name)  /* => superman */
    }
  }
}

superhero.rival.show()

Can you predict the output of the last line?? Read the rule and think again, the output will be superman because we're referring to the nested rival object when calling show().

โš ๏ธ Gotchas

Get ready to scratch your head, edge cases coming your way.

  • Separating method from the object

// First Example 
const favoriteMovie = {
  name: "The Matrix",
  show() {
    console.log(this === favoriteMovie) /* => false */
    console.log(this === window)  /* => true */
  }
}

const showAgain = favoriteMovie.show
showAgain()  /* call-site */

// Second Example => passing the method as a callback
function displayFavoriteMovie(fn) {
  fn(); /* call-site */
}

const favoriteMovie = {
  name: "The Matrix",
  show() {
    console.log(this) /* => window object  */
  }
}

displayFavoriteMovie(favoriteMovie.show)

// Third Example => method as callback to setTimeout
const favoriteMovie = {
  name: "The Matrix",
  show() {
    console.log(this === window) /* => true  */
  }
}

setTimeout(favoriteMovie.show, 200) /* call-site */

If you consider the first example, you can see that showAgain() is called as a standalone function, here rule 1 comes into the picture. In the first example, this refers to the window object because the method lost its binding, it goes back to default binding.

The second example is a little bit tricky, it basically passes the show() method of object favoriteMovie as a callback to another function. In this kind of case, it is super important to recognize the call-site of the method. If you look closely at the call site, the method show() is called as a standalone function. Hence it refers to the window object.

If you consider the third example, you will see that the method show() is passed as a callback to the setTimeout() function, the call site will be equivalent to the below code, this will refer to window object.

setTimeout(function() {
  console.log(this)
}, 200)

Time for a quick reminder -

Don't forget to recognize the call-site

  • "this" in an inner function

    Suppose we have nested functions inside an object, in that case, what will be the value of this? Let's see through some code!
const favoriteMovie = {
  name: "The Matrix",
  show: function () {
    console.log(this === favoriteMovie); // => true

    function innerShow() {
      console.log(this === favoriteMovie); // => false
      return this.name; // => undefined
    }

    return innerShow();
  },
};

favoriteMovie.show();

In the above example, the innerShow() function is called as a regular function. this always refers to the window object in a regular function.

Conclusion

Play around with more test cases around these two bindings, it will help you to build a strong foundation about this and the misconceptions around it. The rest of the article is continued in the second part of this series where we will cover - explicit binding, new binding, and this in arrow functions.

Till then, good luck on wrapping your head around this! (pun intended)