Understanding the "this" keyword in JavaScript

Understanding the "this" keyword in JavaScript

In JavaScript the ‘this’ keyword is one of most widely used keyword and is still quite confusing for most beginners. The value of 'this' is decided based on how the code is being executed or called. The ‘this’ keyword is the object that the function(method) is a property of, it acts as a placeholder and will refer to the object that called the method. In most cases, the value of this is determined by how a function is called (runtime binding). In this article, we’re going to learn about the ‘this’ keyword and how the value of this is assigned in different scenarios. The best way to digest the content of this article is by quickly executing the code snippet in your browser’s console. Follow the below steps to launch the console in your

Chrome browser:

  • Open new tab in Chrome

  • Right click on page, and select “inspect element” from the context menu

  • Go to the console panel

  • Or press the keyboard shortcut Ctrl Shift J (on Windows) or Cmd + Option J (on Mac).

Firefox browser:

You can open the Browser Console in one of two ways

  • Select “Browser Console” from the Web Developer submenu in the Firefox Menu (or Tools menu on macOS).

  • Or press Ctrl + Shift + J (on Windows) or Cmd + Shift + J (on Mac)

Global context

In the global execution context, this refers to the global object.

console.log(this === window); //prints true

var carBrand = 'Toyota';

function getCarBrand() {
    var carBrand = 'Honda';

    console.log('this.carBrand:', this.carBrand); //prints this.carBrand : Toyota
}
getCarBrand();

In this example, ‘this’ refers to the window object therefore printing Toyata variable,

Function context

Inside a function, the value of this depends on how the function is called or invoked. Since the following code is not in strict mode, and because the value of this is not set by the call, this will default to the window object. To set the value of this to a particular value when calling a function, use call(), or apply(). Let see some examples on the function context:

function whatsThis() {
    console.log(this); //prints window object 
    console.log(this === window); //Prints true 
} 
whatsThis(); //Prints true into the console since the value of this in a global-execution context is true.

example two:
var carBrand = 'Toyota';
function getCarBrand() {
    var carBrand = 'Honda';
    console.log('carBrand ', carBrand); //prints carBrand Honda
    console.log('this.carBrand', this.carBrand); //prints this.carBrand Toyota
}
getCarBrand();

Prints CarBrand Honda for the first scenario because of local scoping of variables but with the ‘this’ keyword in second scenario the value of carBrand is Toyota because ‘this’ is attached to the window object.

When in strict mode

If strict mode is enabled for any function, then the value of this will be marked as undefined. The global object refers to undefined in place of the windows object. A function's this will be undefined if not set when entering the execution context in the strict mode. For example:

function whatsThis() {
    'use strict';
    console.log(this); //prints undefined 
    console.log(this === window); //Prints false
}
whatsThis(); //Prints false into the console since in strict mode the value of this in a global-execution context is undefined.    

example two:
var carBrand = 'Toyota';
function getCarBrand() {
    'use strict';
    var carBrand = 'Honda';
    console.log('carBrand ', carBrand); //prints carBrand Honda
    console.log('this.carBrand', this.carBrand); //prints undefined
}
getCarBrand();

Prints undefined into the console since in strict mode the value of this in a global-execution context is undefined.

Note: The statement "use strict" instructs the browser to use the Strict mode, which is a reduced and safer feature set of JavaScript.

Arrow function context

In arrow functions, 'this' retains the value of the enclosing lexical context's this. For example:

'use strict';
const obj = { // does not create a new scope
  a: 10,
  b: () => console.log(this.a, this),
  c: function () {
    console.log(this.a, this);
  },
}

obj.b(); // prints undefined, Window
obj.c(); // prints 10, Object

Arrow functions do not have their own this, an arrow function's this refers to the global object unless wrapped inside a regular function call, whose 'this' refers to the object it's called from and its lexical context is retained by the arrow function.

Event handler context

When we use the ‘this’ keyword in an event handler it refers to the HTML element which triggered the function. Whereas ‘this’ in a function that is used as an event handler for an event refers to the window object. It is recommended to use addEventListener() method to set the event handler because some browser does not allow this convention For example:

/*=====This keyword in inline event handler=====*/
<button onclick="this.innerHTML = 'Button Clicked!'">Show this!</button>
//’this’ refers to the button clicked

example two:
/*=====This keyword in event handler attached using HTML attribute=====*/
<button onclick="ShowThis()">Show this!</button>
<script>
  function ShowThis() {
    console.log(this) //prints Window Object
  }
</script>

In the above examples when the event handler is added to the element using addEventHandler method then this represents the element itself however when you add event listener using a function then this in the function does not represent the element but it represents the Global object.

Object context

When a function is called as a method of an object, this refers to the object the method is called on. This applies to methods defined anywhere in the object's prototype chain (i.e. own and inherited methods).
For example:

function Car(brand, country) {
    this.brand = brand;
    this.country = country;
    this.introCar = function() {
        console.log(`Brand: ${this.brand} from ${this.country}`);
    }
}

let firstCar = new Car("Toyota", "Japan");
firstCar.introCar();  // Prints Brand: Toyota from Japan
let secondCar = new Car("Audi", "Germany");
secondCar.introCar();  // Prints Brand: Audi from Germany

In the example this refers to Car object, firstCar.introCar printed Toyota as it brand because ‘this’ refers to a new instance Car, and in case of secondCar.introCar, this refers to a different instance whose brand is Audi.

Setting "this" using call(), apply() and bind() method

There are three methods in Javascript which help us to set "this" value, it’s the call(), apply() and bind(). Sometimes it happens that we want to borrow a method from the object and use it with another object. Methods like call(), apply(), and bind() can refer ‘this’ to any object. The call and apply method executes the function immediately after setting this of another object to the function but bind does not invoke immediately, you can call it later which makes it suitable to be used as callback functions.

Using the Call() method

The call() allows for a function/method belonging to one object to be assigned and called for a different object. call() provides a new value of this to the function/method. With call(), you can write a method once and then inherit it in another object, without having to rewrite the method for the new object. Call() borrow an object's function from another object and it 'this' will bind to the borrower. For example:

name = "Xavi";
age = 40;
let user1 = {
    name: "Joe",
    age: 25
}

let user2 = {
    name: "Henry",
    age: 30
}

function intro() {
    console.log("My name is " + this.name + " age: " + this.age + " years")
}

intro(); //Prints Global this (Xavi age: 40 years)
intro.call(user1); //Prints this of user1(My name is Joe age: 25 years)
intro.call(user2); //Prints this of user2(My name is Henry age: 30 years)

Using the Apply() method

Let’s take a look at the next method, apply(). This method is very similar to call(), it also lets us change this value and invokes function immediately after it is used, but there is a small difference between them. While passing arguments to call() method, it looked like this: call(newThis, arg1, arg2, arg3). In case of an apply() function instead of passing each argument separately, we can pass them as an array, like this: apply(newThis, [arg1, arg2, arg3]). For example:

name = "Xavi";
age = 40;
let user1 = {
    name: "Joe",
    age: 25
}

let user2 = {
    name: "Henry",
    age: 30
}

function intro() {
    console.log("My name is " + this.name + " age: " + this.age + " years")
}

intro(); //Prints Global this (Xavi age: 40 years)
intro.apply(user1); //Prints this of user1(My name is Joe age: 25 years)
intro.apply(user2); //Prints this of user2(My name is Henry age: 30 years)

Binding this using bind() method

bind() method bind this of another object and returns a new function. Unlike call and apply methods, bind does not invoke immediately, you can call it later which makes it suitable to be used as callback functions. For example:

const person = {
    firstName: "Henry",
    lastName: "Doe",
    fullName: function() {
        console.log(this.firstName + " " + this.lastName);
    }
}

const member = {
    firstName: "Xavi",
    lastName: "Alba",
}

let fullName = person.fullName.bind(member);
fullName() //Prints Xavi Alba

Why use the this keyword

1. It helps execute same code for multiple Object

The 'this' Keyword make our codes more reusable, it helps us structure our code in a way that we can use it for multiple objects and incase our variable or block of code referencing to that variable changes we don't have to update every piece of code refering to that variable, usually this is how to access the properties within an object

let soccerPlayer = {
  name: "Xavi",
  num: 6,
  sayName: function() {console.log("The name of this player is " +  soccerPlayer.name + " wears jersey number " + soccerPlayer.num + ".");}
};
soccerPlayer.sayName() //Prints The name of this player is Xavi wears jersey number 6.

The example above is a valid way to access the object's property but there is a pitfall here. If the variable name changes to let say handballPlayer, any code referencing the original name would need to be updated as well. In a short object definition, it isn't a problem, but if an object has many references to its properties there is a greater chance for error and the 'this' keyword helps to fix that.

let soccerPlayer = {
  name: "Xavi",
  num: 6,
  sayName: function() {console.log("The name of this player is " +  this.name + " wears jersey number " + this.num + ".");}
};
soccerPlayer.sayName() //Prints The name of this player is Xavi wears jersey number 6.

Example two:
//It helps execute same code for multiple Object
function User(name, age, greeting) {
    this.name = name;
    this.age = age;
    this.greeting = greeting;
    this.sayHi = function() {
        console.log(`${this.greeting} My name is ${this.name}, I'm ${this.age}years old.`);
    };
}

let engUser = new User('George', 24, 'Hello');
let espUser = new User('Alba', 25, 'Holla');

engUser.sayHi() //Prints Hello My name is George, I'm 24years old.
espUser.sayHi() //Prints Hello My name is Alba, I'm 25years old.

2. It gives methods access to their object

//It gives methods access to their object

function first() {
'use strict';
console.log("Simple function call")
console.log(this === window); 
}

let user = {
count: 10,
first: first,
second: function() {
console.log(this === window);
    }
}

user.first()  // Prints false because now “this” refers to user object instead of global object.
let newFunc = user.second;
newFunc() // Prints true as this method is invoked as a simple function.
user.second()  // Prints false on console as second() is invoked as a object’s method

In conclusion In JavaScript, the ‘this’ keyword refers to the object that is currently executing the code. The short version of what this evaluates to is as follows:

thiskeyword.png

  1. By default, this refers to the global or window object.
  2. In a function, when not in strict mode, this refers to the window object.
  3. In a function, when in strict mode, this is undefined.
  4. In an arrow function, this retains the value of the enclosing lexical context's this.
  5. In an object method, this refers to the object the method was called on.
  6. In a constructor call, this is bound to the new object being constructed.
  7. In an event handler, this refers to an element that received the event.
  8. When a function is called with the new operator, then this refers to the newly created instance.
  9. When a function is called using the call and apply methods, then this refers to the value passed as the first argument of the call or apply method.