JavaScript | Complete Guide to Understanding “This” Keyword

Javascript is becoming more popular for building web applications and mobile apps using React Native framework. Therefore, understanding its key concepts can come in quite handy. The “this” keyword in Javascript is a source of confusion and misery for most beginner Javascript developers and even pro-developers. This post aims to give you a beginner-friendly comprehensive guide on “this” keyword in Javascript.

The “this” keyword in Javascript refers to the object that owns the Javascript function currently being executed. In other words, “this” is a reference to the current execution context of the function.

Don’t panic if you find this definition a little complex to grasp. This post will break down the “this” keyword into smaller bits that you can easily understand. It will also include code snippets that will give you a deeper understanding of how to use “this” in your Javascript code.

Execution Context

One of the statements used to define “this” keyword in this post is, “whenever a function is executing in Javascript, it has a reference to its current execution context – called “this.” So, what is Execution Context? And how does it relate to the “this” keyword?

The execution context is like a wrapper (or a box) in which your Javascript code executes. It contains information and details about the environment of the current code in execution.

This post will use the Global Execution Context (GEC) as an example to understand the term Execution Context better. GEC is the default execution context where all Javascript code outside a function is executed. See the illustration below of the Global Execution Context.

Global Execution Context
  • Global Object: That is the object that exists in the Global Scope. In this case, it’s the browser window object.
  • This“: The “this” keyword is a variable provided in every execution context and refers to the object currently executing your bit of Javascript code. In this case – it refers to the “global object.” On a browser, that would be the “window object.” In NodeJS, it would be the special object called ‘global.’
  • Variable Environment: Also known as “memory.” It stores all the variables and functions in your code as key-value pairs.
  • Outer Environment: Every execution context has a reference to the outer environment, also known as the Lexical Environment.

What is “this“?

Now that you understand the “Execution Context,” you can now go to the next statement used to define the “this” keyword.

this” refers to an object – that object that is currently executing your bit of Javascript code.

In the Global Context Execution illustration above, “this” refers to the “global object,” which is the “browser window object.”

With that information, you can now derive more definitions of the “this” keyword in Javascript.

  • By default, the “this” keyword refers to the global object.
  • When used in a regular function (not in strict mode), “this” refers to the global object.
  • When used in a function with strict mode, “this” is undefined.
  • If a function is a method in an object, the “this” keyword will refer to the ‘object’ itself.
  • In event handling, “this” refers to the element that receives the event.
  • In constructor functions, “this” is bound to the object created using the “new” keyword.

Tip: A simple trick you can use to understand the “this” keyword easily is – all that matters is how, when and from where a function is called. Not how or where the function is declared or defined.

this” in the Global Context

When the “this” keyword is used outside a function or an object, “this” refers to the ‘global object. If on a browser, “this” will refer to the “window” object. Therefore, you can access methods and properties on that window object. These include “alert,” “setTimeout,” “scroll” etc.

In the case of NodeJS, the global object is no longer the “browser window.” Instead, “this” will refer to a special object called “global.” Similar to the “window object”, the “global object” in NodeJS gives you access to various methods. They include “_dirname,” “_filename,” “process,” “setTimeout” and many more.

Have a look at the code below.

let a = this
console.log(a)

/*---Output---
Window {0: global, window: Window, self: Window, document: document, name: '', location: Location, …}

After running the code above on a browser console, we got an output of the “window object.” That’s because our code is executed in the global context, and ‘this’ refers to the ‘global object’ – the “browser window” in this case.

We can compare the “this” keyword and the “window” object and see whether we will get a boolean True or False.

let a = this;
console.log(a === window);
console.log(a.document === document);//Here, document is a value in the 'window object'

/*---Output---
true
true

We got an output of “true” for both. Let’s look at something much more interesting.

this.a = "Hey developer";
console.log(window.a)

/*---Output---
Hey developer

So, what is happening here? the first line adds an element to the ‘global object’ using the statement this.a = "Hey developer". Next, since “this” refers to the “window object,” you can access the newly added element using window.a. When you console.log(this) on the browser console, you can see the element that was added inside the “window object.”

log window object

this” in Function Context

When used on functions, the behavior of the “this” keyword depends on whether the function is using “strict mode” or not.

this” in a Function (without strict mode)

When used in a regular function without strict mode, the “this” keyword will always refer to the global object, which is the “window object” in the case of browsers. The window object in this scenario is the owner of our function – myFunc().

Note: here, we are talking about a stand-alone function that is not affiliated with any object.

function myFunc(){
 return this;
}
console.log(myFunc());
myFunc() === window;

/*---Output---
Window {0: global, window: Window, self: Window, document: document, name: '', location: Location, …}
true

this” in a Function (with strict mode)

When a function is used in strict mode, Javascript does not allow default binding. Therefore, the “this” keyword here is “undefined.” See the code snippet below.

function myFunc_2(){
    "use strict"
    return this;
}
console.log(myFunc_2());
myFunc_2 === window

/*---Output---
Undefined
false

this” in Function Method Context

In Javascript, objects can consist of simple values or methods. When a function is used inside an ‘object,’ we refer to it as a “method.” If “this” is used inside the method, whenever the method is invoked, “this” will refer to the object upon which the method was invoked. That object becomes the owner of the method.

let fruits = {
   mango:"Yellow",
   lemon:"Green",
   myFunc() {
       console.log(`I Love ${this.mango}`)
    }
}
fruits.myFunc()

/*---Output---
I Love Yellow

Here, “this” refers to the “fruits” object. Let’s tweak the code and see the contents of “this” when the method is invoked.

let fruits = {
   mango:"Yellow",
   lemon:"Green",
   myFunc(){
       console.log(this)
    }
}
fruits.myFunc()
/*---Output---
{ mango: 'yellow', lemon: 'green', myFunc: [Function: myFunc] }

Quite interesting! From the output above, you can see that “this” refers to the “fruits” object upon which the method was invoked – fruits.myFunc(). Below is a more complex example of the “this” keyword when used with “methods.”

function greet(){
   console.log("How are you " + this.name)
}
const person_1 = {
    name:"John Doe",
    greet
}
const person_2 = {
    name:"Mike",
    greet
}
person_1.greet()
person_2.greet()

/*---Output---
How are you John Doe
How are you Mike

Here, the two objects,person_1 and person_2,” both borrow the “greet function.” In the case of person_1.greet(), the thiskeyword refers to the “person_1” object. In person_2.greet(), “this” refers to “person_2” object.

You can verify that by tweaking the code above and seeing the output of “this” as shown below.

function greet(){
   console.log(this)
}
const person_1={
    name:"John Doe",
    greet
}
person_1.greet()

/*---Output---
{ name: 'John Doe', greet: [Function: greet] }

From the output above, you can see that “this” is referencing the “person_1” object.

This section has introduced us to re-usability using the “this” keyword. We have one function greet() that is used with two different objects (person_1 and person_2). From the two code snippets we have looked at, you can deduce that the “this” keyword in a function can have different meanings depending on who is calling it.

Tip: “Who is on the left side rule.
That is another tip you can rely on when working with the “this” keyword. It states – The “this” keyword is the object on the left side of the function invocation.

When you apply that rule to all the above examples up to this point; you will realize the rule applies. In the last code snippet, “person_2” is on the left side of the function invocation.

this” in Arrow Functions

Arrow functions were introduced in ES6. Unlike regular functions, arrow functions allow developers to write neat, easy-to-read code. When using “this” with arrow functions, the definitions we have looked at above don’t apply.

That’s because Arrow functions don’t create an execution context. Therefore, they don’t have their own “this.” Instead, they inherit the “this” of the outer function where they are defined. Take a look at the code below to have a better understanding.

let fruits = {
  mango: 'Yellow Mangoes',
  sayColor() {
    mango: 'Green Mangoes';
    let myFunction = () => console.log(`I Love ${this.mango}!`);
    myFunction();
  }
};
fruits.sayColor();

/*---Output---
I Love Yellow Mangoes!

From the output above, you can see that the “this” keyword in arrow functions refers to the object that defined the arrow function. In this case, it’s the ‘fruits’ object.

If instead, you were to log “this” in the arrow function let myFunction = () => console.log(this), you would get the result below.

{ mango: 'Yellow Mangoes', sayColor: [Function: sayColor] }

this” With the Call and Apply Methods

When a function uses the “this” keyword in its body, its value can be bound to a particular object when invoked by using the call() and apply() methods. Have a look at the code snippet below.

function add(num1, num2){
    let c = this.a + this.b + num1 + num2;
    console.log(c)
}
const myObj = {a:7, b:9};
add.call(myObj,10, 12)

/*---Output---
38

F focus on the add.call(myObj,10, 12) line. The first parameter of the call() method is the object the function will use as “this.” In this case, it’s the ‘myObj’ object. The other arguments (10, 12) are passed to add() function as parameters – num1 and num2 respectively.

The apply() method is similar to the call() method. The only difference is that call() method accepts an argument list while the apply() method accepts a single array of arguments. Replace the call() method above with apply() as shown below.

function add(num1, num2){
    let c = this.a + this.b + num1 + num2;
    console.log(c)
}
const myObj = {a:7, b:9};
add.apply(myObj,[12,15])

/*---Output---
43

this” with the Bind() Method

When you call the bind() method on a function and pass an object, it creates a new function with the same body scope as the original function. But where “this” occurs in the original function, in the new function, “this” is permanently bound to the first argument of the bind().

function myFunc() {
  return this.name;
}

var greet = myFunc.bind({name: 'Hello John'});
console.log(greet());

/*---Output---
Hello John

In the code above, “this” refers to the object {name: 'Hello John'}, which is the argument passed in the bind method. Look at a more complex illustration of the bind() method below.

function Fruit(var1, var2) {
	this.fruitOne = var1;
	this.fruitTwo = var2;

	this.displayName = function() {
		console.log(`I Love: ${this.fruitOne} and ${this.fruitTwo}`);
	}
}

let fruit_1 = new Fruit("Mangoes", "Melons");
fruit_1.displayName(); //I Love: Mangoes and Melons
let fruit_2 = new Fruit("Apples", "Amanatsu");
fruit_2.displayName(); //I Love: Apples and Amanatsu

let person2Display = fruit_1.displayName.bind(fruit_2)
person2Display(); //I Love: Apples and Amanatsu

/*---Output---
I Love: Mangoes and Melons
I Love: Apples and Amanatsu
I Love: Apples and Amanatsu

In the code above, the line fruit_1.displayName.bind(fruit_2) creates a new function with value of “this” equals to “fruit_2” object.

this” in Callback Functions (Problem)

Take a look at the code below where we are calling “this” in a callback function.

const fruits = {
    Orange: "Yellow",
    sayColor: function () {
        setTimeout(function() {
            console.log("I Love Color " + this.Orange)
        }, 100)
    }
}
console.log(fruits.sayColor())
/*---Output---
undefined
I Love Color undefined

From the output above, you can now see the inconsistency with the “this” keyword in Javascript and why it becomes confusing to most developers. “this” in the setTimeout() function is undefined.

That goes against our definition where we said – “this” will refer to the object upon which the method was invoked. It also goes against the rule “Who is on the left side.” There are three main ways to fix that.

  • Explicitly setting “this.”
  • Using Arrow function
  • Using bind()

Solution 1: Explicitly setting “this.

Before ES6 and Arrow functions, developers used a technique of storing a reference to “this” in a variable. Therefore, one could simply call the variable whenever they wanted to use “this” in their code.

To apply this solution in the code above, you will need to create a variable called “self” in the sayColor() function and set it to “this.”

const fruits = {
    Orange: "Yellow",
    sayColor: function () {
        let self = this; //Store a refernce to 'this' in a variable
        setTimeout(function() {
            console.log("I Love Color " + self.Orange)
        }, 100)
    }
}
fruits.sayColor()
/*---Output---
I Love Color Yellow

As you know, “this” refers to the object upon which the method was invoked. In the code above, we invoked the sayColor() function on the fruits object. Therefore, “this” will refer to the “fruits” object. But since “this” is not accessible in the callback function, we saved a reference to “this” in the “self” variable.

We can now proceed to use “self” in our callback function or any other section of our code.

Solution 2: Using Arrow Functions

In the previous sections when looking atthe relation of “this” and Arrow functions, this post stated that – arrow functions inherit the “this” of the outer function where they are defined. Using that concept, you can quickly solve the problem present here. You will covert the callback function to use an arrow function syntax.

const fruits = {
    Orange: "Yellow",
    sayColor: function () {
        setTimeout(()=>console.log("I Love Color " + this.Orange),100)
    }
}
fruits.sayColor()

/*---Output---
I Love Color Yellow

Pretty clean and straightforward. What exactly is happening here?

The “this” in the setTimeout() arrow function refers to the object where the arrow function is defined. In this case, it’s the “fruits” object.

Solution 3: Using the Bind() Method

Of the three solutions, bind() is the most technical of all. Earlier when working with the bind() method, this post stated that – “When you call the bind() method on a function and pass an object, it creates a new function with the same body scope as the original function.”

In this scenario, the solution would be to bind the setTimeout() function to the “fruits” object by passing “this” as an argument in the bind() method.

const fruits = {
    Orange: "Yellow",
    sayColor: function () {
        setTimeout(function() {
            console.log("I Love Color " + this.Orange)
        }.bind(this), 100)//Here, we are binding the setTimeout() function to the fruits object.
    }
}
fruits.sayColor()

/*---Output---
I Love Color Yellow

this” in Constructor Functions

Calling a function with the “new” keyword turns the function into a constructor. Constructor functions automatically create a binding between the object being created using the “new” keyword and the “this” keyword on the inside of the function. Take a look at the code below.

function Fruit(a){
    this.name = a;
    this.sayFruit = function(){
        console.log(this) //Here, we want to see the value of "this"
        console.log(`I Love ${this.name}`)
    }
}
const newFruit = new Fruit("Mangoes"); //Here, we create a binding between the newly created object "newFruit" and the "this" keyword.
newFruit.sayFruit()

/*---Output---
Fruit { name: 'Mangoes', sayFruit: [Function] }
I Love Mangoes

When you take a keen look at the code above, you will also notice that the “who is on the left rule” applies here.

this” in Event Handlers

When used in inline event handling, the “this” keyword refers to the DOM element that is receiving the event. Assume we want to create a button that, when clicked, its display property is set to “none.” How, would you go about it?

<button onclick="this.style.display='none'">
  Button Me!
</button>

In the above code snippet, “this” refers to the button element.

“this” in event handling

this” Keyword Precedence

There are cases where it’s hard to determine which object “this” refers to, especially when an application has a lot of asynchronous code. To solve that, “this” follows an order of precedence, as shown in the table below.

PrecedenceObject
1bind()
2call() and apply()
3object method
4Global scope
this” order of precedence
  • In a function, is “this” called using the bind() method?
  • In a function, is “this” called using the apply() method?
  • In a function, is “this” called using the call() method?
  • In a function, is “this” inside a function in an object (method)?
  • In a function, is “this” in the Global Scope?

Conclusion

Although the “this” keyword can be quite confusing, this post has given you enough tips and tricks to help you understand the concept better. Try out more examples other than only those provided in the code snippets in this post. That way, you will have a solid understanding of how the “this” keyword works.

Was this article helpful? Do you have any comments or suggestions?

Let us know by replying on Twitter of Become A Better Programmer or to my personal Twitter account.