Function Context

Each function has an execution context which is exposed to the function via the this keyword. You can explicitly bind a function to an execution context using Function Instance Methods call, apply and bind.

const account = {
  balance: 100,
}

function displayBalance () { 
  console.log(this.balance); 
}

displayBalance();
displayBalance.bind(account)();

The bind() method creates a new function that and sets the this keyword to the provided value.

function greet() {
  console.log(`Welcome to ${this.name}`);
}

const cs280 = { name: "Full-Stack JavaScript" };
const cs226 = { name: "Data Structures" };

const greet280 = greet.bind(cs280);
const greet226 = greet.bind(cs226);

greet280();
greet226();

The calls() method calls a function and sets the this to reference the provided value as execution context. If the function takes in more arguments, those arguments can be passed (in order) following the first argument.

const account = {
  balance: 100,
}

function deposit (amount) { 
  this.balance += amount; 
}

function withdraw (amount) { 
  this.balance -= amount; 
}

deposit.call(account, 50);
withdraw.call(account, 20);

console.log(account.balance);

The apply() method calls a function with a given execution context, and the function arguments are provided as an array (or an array-like object).

const stats = {
  max: Number.MIN_SAFE_INTEGER,
  min: Number.MAX_SAFE_INTEGER
}

function max(...args) { 
  for(let i = 0; i < args.length; i++) {
    if (this.max < args[i]) {
      this.max = args[i];
    }
  }
}

function min(...args) { 
  for(let i = 0; i < args.length; i++) {
    if (this.min > args[i]) {
      this.min = args[i];
    }
  }
}

const numbers = [5, 6, 2, 3, 7];
max.apply(stats, numbers);
min.call(stats, ...numbers);
console.log(stats);

Arrow functions are not suitable for call, apply, and bind methods, which generally rely on establishing a scope.