DEV Community

Cover image for this in JavaScript. The only article you need to read.
Ayilara Sodiq
Ayilara Sodiq

Posted on

this in JavaScript. The only article you need to read.

If you are like me, you have spent several hours trying to understand this. You have heard terms like, a function binds its own this, and you didn't get it. I have been there, that is why I am writing this article. The goal is to help you understand the concept in simple, clear terms.

This article is targeted at the following groups:
• junior developers
• senior developers

The following are the prerequisite knowledge required:
• Functions in JavaScript
• An understanding of the window object
• Class syntax in JavaScript
• Objects in JavaScript
• Event listeners in JavaScript

This article does not cover advanced edge cases of the this keyword, please read the docs here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this.

The article is in two parts:

Part 1, discusses the everyday use of this:
• what is this
• this in regular functions

Part 2 covers the following:
• this in arrow functions
• this in special cases

What is this? this is a special keyword in JavaScript. It always refers to an object, without exception. So, we have solved the first part, this is a pointer in JavaScript. Onward, we go. The second part, this is always declared in a function. This is key to understanding this. For clarity, here are the rules again:

• this is always a pointer to an object.
• this is always defined inside a function.

Let's see a quick example:

let obj = {

country : 'nigeria',

getCountry(){
return this.country;
}
};

Enter fullscreen mode Exit fullscreen mode

Don't worry about the code, it will be explained, just observe that this is in a function, and it refers to the object- obj.

Regular functions(for simplicity, will refer to any function other than arrow functions) and this. Read closely here. When thisis defined in a regular function, it points to the object that invokes the function. In other words, it points to the object which called the function. This means that this in a regular function is NOT sure what to point to until the function is invoked. Consider the simple example above:

• A function inside an object like this is called a method.

this in the getCountry function doesn't know what object to point to just yet, it's as confused as you and I.

• the value of this becomes clear to JavaScript, when you invoke(run or call) the function.

• the value of this, is set to the object that directly calls the function.

• So, to call the getCountry method, we write:

obj.getCountry();
Enter fullscreen mode Exit fullscreen mode

• Guess what this refers to.

• Yes, it refers to the obj object, as it was the object that called the function getCountry.

• Hence, the output will be: nigeria.

Let's consider something more interesting. Given the following expressions, determine the output, and explain why. Try this yourself, before seeing my explanation.

First example:

function logger(str){
    return this.str;
}

logger(‘John’) // ??

Enter fullscreen mode Exit fullscreen mode
Second example:

let obj = {
  name : 'John',

  getName(){

    function anotherFunc(){
      return this.name;
    }

    return anotherFunc();
  }
}

obj.getName() // ??

Enter fullscreen mode Exit fullscreen mode

How did that go? It doesn't matter, so long you tried. Now, let's consider the first example:

• When you call the function, logger, what happens?

• All JavaScript functions run within an object behind the scenes. This object is referred to as the context of the function.

A little trick, to determine the context of a function is to look to the left of the function when it is invoked.

thisalways refers to the context.

• To call the logger function, we write logger();

• In reality, this is is what is happening : window.logger();

• This is because the windowobject is the closest object to the function, hence it is its context.

• The function logs undefined, as the str property doesn't exist on the window object.

• If we remove the strparameter from the function, and just return this, you get the windowobject.

In this second example, to access the getName method, we write obj.getName(),but we get undefined as our result. This happens because our method returns another function. A function nested inside of the getName method- a nested function. The nested function is the one with this.
What does this point to? Well, let's try to call the nested function and then look left.

obj.getName.anotherFunc()
Enter fullscreen mode Exit fullscreen mode

As you can see, the closest caller of the anotherFunc function is not an object but a method: getName. But this doesn't point to a function, ever. What is really happening?
Well, this is it:

obj.getName.window.anotherfunc
Enter fullscreen mode Exit fullscreen mode

Hence the object closest to anotherFunc is the window.
This object doesn't have a name property on it, so it returns undefined.

This logic is true for all regular functions nested in a method, no matter how deep the nesting, the context is always the window object. You can try this out yourself.

We have discussed some key concepts thus far, I advise you to practice some questions at this point to test your understanding.
Try these two(answers are immediately after both questions):

Question 1:

const object = {
  message: 'Hello, World!',
  getMessage() {
    const message = 'Hello, Earth!';
    return this.message;
  }
};
console.log(object.getMessage()); // What is logged?
Enter fullscreen mode Exit fullscreen mode
Question 2:

const object = {
  message: 'Hello, World!'
};

function logMessage() {
  console.log(this.message); // 
}

logMessage();  // ??

Enter fullscreen mode Exit fullscreen mode

These questions are gotten from Dmitri Pavlutin, you can check out his blog here for more : https://dmitripavlutin.com/javascript-this-interview-questions/

Answer to question 1:

Hello, World!

Answer to question 2:

undefined

The concepts that we have discussed so far are the natural ways this works. This is what is called implicit binding of this. But sometimes, we want to force this to behave in a more flexible manner. For example, in the anotherFunc above, say we want this to point obj, rather than the window object. Well, we must explicitly tell JavaScript to do that.

Explicit this binding can be achieved in one of three simple ways:

call(context, arg)
apply(context, [arg])
bind(context, arg)

The call method is applied to a function to change the context of the function i.e to change what this is points to. We can change it to whatever we like.

To change anotherFunc to reference our objobject, we reframe our object like this:

let obj = {
  name : 'John',
  getName(){

    function anotherFunc(){
      return this.name;
    }
    return anotherFunc.call(obj);
  }
}

obj.getName() // "John"
Enter fullscreen mode Exit fullscreen mode

The second parameter of the call method is args, which refers to the argument you want to pass into the function. Here is an example:

function welcome(event){
  return 'Hello ' + this.name + ' welcome to the ' + event
}

let obj = {
  name : 'John'
}

welcome.call(obj,'Oscars'); //

'Hello John welcome to the Oscars'

Enter fullscreen mode Exit fullscreen mode

The apply method works exactly like the call method ,except it takes args in the form of an array. For example:

function welcome(a, b, c){
  console.log('Hello ' + this.name + ' welcome to the ' + a);
  console.log('Hello ' + this.name + ' welcome to the ' + b);
  console.log('Hello ' + this.name + ' welcome to the ' + c);
}

let obj = {
  name : 'John'
}

let events = ['Grammy', 'Oscars', 'World cup'];

welcome.apply(obj, events);

// Hello John welcome to the Grammy
// Hello John welcome to the Oscars
// Hello John welcome to the World cup


//a, b, and c ---> the indices of the events elements.
Enter fullscreen mode Exit fullscreen mode

The bind method works like the call method, however it returns a new function that can be called later. For example:

function welcome(event){
  return 'Hello ' + this.name + ' welcome to the ' + event
}

let obj = {
  name : 'John'
}

let bindFunc = welcome.bind(obj,'Oscars'); 

bindFunc(); //


'Hello John welcome to the Oscars'
Enter fullscreen mode Exit fullscreen mode

I hope this article, has clarified this for you. Part 2 will go into some quirky parts of this, for now, cheers and see you soon.

Latest comments (0)