Function Context

Inside a function, the value of this depends on how the function is called.

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 global object, which is window in a browser.

function f1() {
  return this;
}

// In a browser:
f1() === window; // true

// In Node:
f1() === globalThis; // true

In strict mode, however, if the value of this is not set when entering an execution context, it remains as undefined, as shown in the following example:

function f2() {
  'use strict'; // see strict mode
  return this;
}

f2() === undefined; // true

Method Calls

When a function is called on an Object, this binds itself to that object.

const person= {
    firstName: "John",
    sayHi() {
        console.log(`Hi ${this.firstName}!`);
    }
};

person.sayHi(); // Hi John

const greet = person.sayHi;
greet(); // Hi undefined

setTimeout(person.sayHi, 1000); // Hi undefined
setTimeout(function () {
    person.sayHi();
}, 1000); // Hi John

setTimeout(person.sayHi.bind(person), 1000); // Hi John

Arrow Functions

Arrow Functions don't have this. They use the value of this from outer function.

const outerThis = this;

const func = () => {
    console.log(this === outThis);
};

func();  // true

Using methods like call, apply, and bind won't have any effect on arrow functions. They simply ignore them.

call and apply

We can explicitly set this to a particular value using call and apply methods.

function sayHi() {
    console.log(`Hi ${this.firstName}!`);
}

const person = {
    firstName: "Jane"
}

sayHi.call(person); // Hi Jane
sayHi.apply(person); // Hi Jane

Difference b/w call and apply

call expects a comma-separated list while apply expectes an array.

const numbers = [10, 20, 30, 40, 50];

const slice1 = numbers.slice(1, 4);
const slice2 = numbers.slice.call(numbers, 1, 4);
const slice3 = numbers.slice.apply(numbers, [1, 4]);