Understanding "this " Keyword and Arrow Functions in JavaScript

Understanding "this " Keyword and Arrow Functions in JavaScript

The this keyword refers to the context where a piece of code, such as a function's body, is supposed to run. Most typically, it is used in object methods, where this refers to the object that the method is attached to, thus allowing the same method to be reused on different objects.

Example:

const user = {
    username: "harsh",
    price: 999,
    welcomeMessage: function(){
        console.log(`${this.username}, welcome to the website`);
        console.log(this); // Provides the current context
    }
}

user.welcomeMessage(); 
user.username = "sam"; // Context changed here
user.welcomeMessage();
//output
harsh, welcome to the website
{ username: 'harsh', price: 999, welcomeMessage: [Function: welcomeMessage] }
sam, welcome to the website
{ username: 'sam', price: 999, welcomeMessage: [Function: welcomeMessage] }

Here, this inside the welcomeMessage method refers to the user object. After changing user.username to "sam", the this keyword still refers to the user object, reflecting the updated username, or we can this refers to the current context.

this in Global Context and Functions

When you use this outside of any object or function, or within a regular function in the global context, it behaves differently.

console.log(this); // Prints the current context in Node.js, which is an empty object

function chai(){
    let username = "harsh";
    console.log(this.username); // Prints undefined
    console.log(this); // Prints the global object in Node.js
}
chai();

//********also if we declare function this way, output will be same****
console.log(this);
const drinks = function(){
     let drinkName = "chai";
     console.log(this.drinkName);
 }

drinks();
//output
{}
undefined
<ref *1> Object [global] {
  global: [Circular *1],
  clearInterval: [Function: clearInterval],
  ...
}
  • When a function is called in the global context (not as a method of an object), this refers to the global object.

  • In a browser, the global object is window. In Node.js, the global object is global.

  • In Node.js, this in the global context refers to an empty object ({}), not the global object directly.

  • However, within a function, this still refers to the global object.

  • Regular functions have their own this context, which is determined by how they are called.

  • If a function is called as a standalone function (not as a method of an object), this refers to the global object.

  • When chai is called, it is invoked as a standalone function, and in that case "this" refers to the global object and the global object does not have any property called as username, therefore leading to print undefined in the case of "console.log(this.drinkName)".

Arrow Functions and this

Arrow functions differ from regular functions in how they handle the this keyword. They do not have their own this context; instead, they inherit it from the parent scope.

Example:

const drinks = () => {
    let drinkName = "fanta";
    console.log(this);  // Inherits `this` from the parent scope, which is an empty object in Node.js
    console.log(this.drinkName); // Prints undefined
}

drinks();
//outputs: 
// {}
// undefined

In JavaScript, arrow functions do not have their own this context. Instead, they inherit this from the surrounding lexical context. This is one of the main features that distinguish arrow functions from regular functions.

When you define an arrow function and log this inside it, it doesn't create its own this. Instead, it uses this from the scope in which the arrow function was defined.

In this case, the arrow function drinks is defined in the global scope (assuming we are running this in a Node.js environment). In the global scope of Node.js, this refers to an empty object ({}). This is why console.log(this) outputs {}.

More about Arrow Functions

Arrow functions provide a concise syntax and different handling of the this keyword.

Explicit return:

const addTwo = (num1, num2) => {
    return num1 + num2;
}
console.log(addTwo(3,4));
//outputs: 7

Implicit return:

const addTwo = (num1, num2) => num1 + num2;
const addTwo = (num1, num2) => (num1 + num2); //we can also write above line as
console.log(addTwo(3,4));
//outputs: 7

Let's look at the syntax if we want to return an object inside an arrow function

const addTwo = () => {username: "harsh"};
console,log(addTwo());
//outputs: undefined

//***********CORRECT WAY************
const addTwo = () => ({username: "harsh"});
console.log(addTwo());
//outputs: {username: 'harsh'}

Key differences

  • Arrow Functions: Do not have their own this context; they inherit it from the surrounding lexical scope.

  • Regular Functions: Have their own this context, which is determined by how the function is called.