Tips on this, call, apply, and bind

  • Last updated on 19th May 2023

Introduction

When we’re working with JavaScript, call, apply, and bind are methods used to control how a function is executed and what context it runs in. By context, I mean its this value, which refers to the object that is currently executing the function. Using these methods, you can specify which object should be treated as this inside the function, allowing for greater flexibility and control in your code. Practically speaking, this is important because it means we use them to manipulate the execution context of a function, outside of it’s original object.

Practical example

"use strict";

// Define a character object with a method to describe an attack
const character = {
  name: "Ted",
  class: "Warrior",
  attack: function(weapon, damage) {
    console.log(`${this.name} the ${this.class} attacks with a ${weapon} causing ${damage} damage!`);
  }
};

// Another character object
const anotherCharacter = {
  name: "Luna",
  class: "Mage"
};

// Using call to invoke the attack method with a different context
character.attack.call(anotherCharacter, "staff", 15);
// Output: Luna the Mage attacks with a staff causing 15 damage!

// Using apply to invoke the attack method with a different context and an array of arguments
character.attack.apply(anotherCharacter, ["magic spell", 20]);
// Output: Luna the Mage attacks with a magic spell causing 20 damage!

// Using bind to create a new function with a preset context
const lunaAttack = character.attack.bind(anotherCharacter, "wand");
lunaAttack(10); // Later we can specify the damage
// Output: Luna the Mage attacks with a wand causing 10 damage!

// Bind can also preset the context without presetting arguments
const tedAttackWithSword = character.attack.bind(character, "sword");
tedAttackWithSword(25);
// Output: Ted the Warrior attacks with a sword causing 25 damage!

// Using call, apply, and bind together in a practical scenario

// Define a function that logs an action with multiple steps
function performAction(step1, step2, step3) {
  console.log(`${this.name} the ${this.class} starts with ${step1}, then ${step2}, and finally ${step3}.`);
}

// Using bind to set context and partial arguments
const tedPerformAction = performAction.bind(character, "block with shield");

// Using call to invoke the partially bound function with additional arguments
tedPerformAction.call(character, "swing sword", "deflect");

// Using apply to invoke the partially bound function with additional arguments as an array
tedPerformAction.apply(character, ["swing sword", "deflect"]);

// Output (for both call and apply): 
// Ted the Warrior starts with block with shield, then swing sword, and finally deflect.

Above, we have a character object with a method attack that logs an attack message.

Another object, anotherCharacter, represents a different character. Using call, we make anotherCharacter use the attack method: character.attack.call(anotherCharacter, "staff", 15). The apply method does the same but takes arguments as an array: character.attack.apply(anotherCharacter, ["magic spell", 20]).

The bind method creates a new function with a preset context, allowing anotherCharacter to attack later: const lunaAttack = character.attack.bind(anotherCharacter, "wand").

We then use call and apply with bind to perform complex actions: thorinPerformAction.call(character, "swing sword", "deflect") and thorinPerformAction.apply(character, ["swing sword", "deflect"]).

Why is this significant?

Because we can instantiate dynamic context. We also have flexibility in function arguments. call allows us to pass arguments individually, we get fine-tuned control over the function execution. With apply, we can accept arguments in an array format. With this, we can “borrow methods”. This is important because it means we can use a method from one object on another, which helps us avoid redundancy but allows us to reuse code. We’re also able to use the partial function application of it because bind creates a new function that has optional preset arguments.

Until the, have a great day!

Resources