Function & this

Functions are the building blocks of JavaScript, it is one of the programming languages that uses functional programming at the core. As easy as it is to use the functions, understanding this keyword is that complex. Because the value of this is decided at the execution time, unlike other programming languages.

As a Normal Function

The value of this in the function invocation refers to the global object. window in the browser and global in Nodejs.

function normalFunction() {
  console.log(this === window);
  this.name = "Arjunan";
}

normalFunction(); // true
console.log(window.name) // Arjunan

Strict mode

If you invoke the function with the strict mode the value of this will be undefined. It also affects all the inner functions that are defined in the function which is declared in strict mode.

function strictModeExample() {
  "use strict";
  console.log(this === undefined);

  function inner() {
    console.log(this === undefined);
  }

  inner();
}

strictModeExample();

this inside Method

When a function is declared inside an object the value of this inside that function will refer to the object it is declared in.

If the object is passed as a reference, then the context is shared between both the variables, the original and the one that has the reference.

const example = {
  name: "Arjunan",
  showName: function () {
    console.log(this === example);
    console.log(this.name);
  },
};

example.showName();
// true
// Arjunan

example.name = "John Cena";

example.showName();
// true
// John Cena

const example2 = example
example2.name = "Rock"

example2.showName()
// true
// Rock

example.showName()
// true
// Rock

But, if we extract the method and save it in a variable, and then invoke the variable, the outcome will change. This is because when extracted to a variable and invoked it will be treated as a normal function.

const example = {
  name: "Arjunan",
  showName: function () {
    console.log(this === example);
    console.log(this === window);
    console.log(this.name);
  },
};

const show = example.showName;
show();
// false
// true
// undefined

If there are any inner functions inside the methods, the value of this inside them depends upon how the inner function is invoked.

Because the inner function is invoked as a normal function the value of this is a window object.

const example = {
  name: "Arjunan",
  showName: function () {
    function inner() {
      console.log(this === window);
      console.log(this.name);
    }

    inner();
  },
};

example.showName()
// true
// undefined

The fat arrow function does not have this of its own, it accesses this in its nearest scope.

const example = {
  name: "Arjunan",
  showName: function () {
    const inner = () => {
      console.log(this === example);
      console.log(this.name);
    };

    inner();
  },
};

example.showName();
// true
// Arjunan

this when invoked as constructor

The value of this in the function invoked as a constructor refers to a new object which has the value passed as an argument. Each instance creates a new object.

function Example(blog) {
  this.blog = blog;
  this.displayBlog = function () {
    console.log(this.blog);
  };
}
const example = new Example("Apple");
example.displayBlog();
// Apple
const example2 = new Example("Orange");
example2.displayBlog();
// Orange
console.log(example === example2);
// false

There are some methods in JavaScript that when invoked normally behave as a constructor.

let reg1 = RegExp(/[a-z]/i);
let reg2 = RegExp(/[a-z]/i);

console.log(reg1 === reg2);
// false

To avoid this we can add a check to the function which we want to be invoked as a constructor only.

function Example(name) {
  if (!(this instanceof Example)) {
    throw Error("Need to invoke as a constructor");
  }
  this.name = name;
}

const example1 = new Example("John");
console.log(example1.name);
// John

const example2 = Example("Rock");
// Error: Need to invoke as a constructor