Skip to main content

Command Palette

Search for a command to run...

The Magic of this, call(), apply(), and bind() in JavaScript

Updated
8 min read
The Magic of this, call(), apply(), and bind() in JavaScript
V
Vishal Gupta Android dev in progress. Building toward SaaS — one shipped product at a time. I care about reliability over hype. Still learning, but I build things that work.

What is this keyword -

In javascript most confusing topic to understanding this , how this keyword context changes when you use with call() , apply() & apply() . But don't worry i will try to my best break it down and simple and real example .


What is this in JavaScript ?

this = who is calling/running the function .

Real-World Analogy

Imagine in a recipe book . The recipe says "add salt to my pot". But whose pot ?

It depend on Who is using the recipe !

  • If Raghav uses it → my pot = Raghav's pot

  • If Shibu uses it → my pot = Shibu's pot

  • If no one specific uses it → my pot = nobody's pot

That's exactly how this work !

function greet() {
  console.log("I am " + this);
}

greet(); // I am [object global]

Who called ? greet nobody specific → global object

let person = {
  name: "Alice",
  greet: function() {
    console.log("I am " + this.name);
  }
};

person.greet(); // Output: "I am Alice"

Who called greet ? person object --> this = person

let person1 = {
  name: "Alice",
  intro: function() {
    console.log("Hello, I am " + this.name);
  }
};

let person2 = {
  name: "Bob"
};

person1.intro(); // Output: "Hello, I am Alice"


person2.intro = person1.intro;


person2.intro(); // Output: "Hello, I am Bob"

Who call intro first ? person1 --> this = person1

Then , In code person2.intro = person1.intro .

It means we just put intro function defination of person1 inside person2 in their key name intro .

now person2 :

{
    name : "Bob",
    intro : function() {
    console.log("Hello, I am " + this.name);
  }
}

Who call intro ? person2 --> this = person2 .

Same function , Different caller = Different this .

Important Rule: It's About WHO Called It, Not WHERE It's Defined

The location where you write the function , it doesn't matter. What matters is who calls/runs the function.

let teacher = {
  name: "Mr. Smith",
  teach: function() {
    console.log(this.name + " is teaching");
  }
};

let student = {
  name: "John"
};

teacher.teach(); 
// Who teach ? teacher → Output: "Mr. Smith is teaching"

student.teach = teacher.teach;
student.teach(); 
// who teach ? student → Output: "John is teaching"

let func = teacher.teach; 
// teach function defination assign to func
/*
    console.log(`${func}`);
    Output: function() {
        console.log(this + " is teaching");
      }
*/

func();
// Who call func? global object (global object has no name key so give undefined) → Output: "undefined is teaching"

The function not change. Only the caller changed. so this changed!

let animal = {
  sound: "bark",
  makeSound: function() {
    console.log(this.sound);
  }
};

let dog = { sound: "woof" };
dog.makeSound = animal.makeSound;
dog.makeSound(); // Output: "woof"


let cat = { sound: "meow" };
cat.makeSound = animal.makeSound;
cat.makeSound(); // Output: "meow"


let func = animal.makeSound;
func(); // Output: undefined 

Summary:

  • When dog calls it → this = dog

  • When cat calls it → this = cat

  • When nobody calls it → this = global object (global object not have sound key so this.sound --> undefined)

this Inside Arrow Functions

Arrow functions () => {} do not have their own this. Instead, they use this from their parent/outer scope.

Regular Function vs Arrow Function

let person = {
  name: "Alice",
  regularFunction: function() {
    console.log("Regular: " + this.name);
  },
  arrowFunction: () => {
    console.log("Arrow: " + this.name);
  }
};

person.regularFunction(); // Output: "Regular: Alice"
person.arrowFunction();   // Output: "Arrow: undefined"

Why the difference? The arrow function doesn't have its own this. It looks outside the object for this, and outside there is no name property.

Arrow function rule: Looks for this in function scope, not object scope!

let user = {
  username: "Bob",
  greet: function() {
    console.log("1. this in regular: " + this.username);
    
    let arrow = () => {
      console.log("2. this in arrow: " + this.username);
    };
    
    arrow();
  }
};

user.greet();
// Output:
// "1. this in regular: Bob"
// "2. this in arrow: Bob"

Arrow function inside an regular function and regular function own this . So as per definition , arrow function it look for this in parent scope which is greet regular function ./q

Arrow function = "Borrow this from parent function"

Key Point: call(), apply(), bind() Don't Work with Arrow Functions

Arrow functions ignore call(), apply(), and bind() because they don't have their own this to control.

The Problem We Need to Solve

Now, what if we want to use a method from one object with another object?

let person1 = {
  name: "Alice",
  introduce: function() {
    console.log("I am " + this.name);
  }
};

let person2 = {
  name: "Charlie"
};


let func = person1.introduce;
func(); //"I am undefined"

The problem: We lost the connection between the function and person1.

The solution: Use call(), apply(), and bind() to control this!

What call() Does

call() lets you borrow a method from one object and use it with another object immediately.

Syntax:

function.call(thisObject, argument1, argument2, ...);

Example 4: Using call()

let person1 = {
  name: "Alice",
  greet: function(greeting) {
    console.log(greeting + ", my name is " + this.name);
  }
};

let person2 = {
  name: "Charlie"
};

// Borrow greet of person1 method for person2
person1.greet.call(person2, "Hello");
//"Hello, my name is Charlie"

What happened? We told the greet function: Run, but treat person2 as this.

call() with Multiple Arguments

let user = {
  name: "Diana",
  login: function(password, timestamp) {
    console.log(this.name + " logged in with password and timestamp: " + timestamp);
  }
};

let admin = {
  name: "Eve"
};

user.login.call(admin, "secret123", "2024-03-05");
// "Eve logged in with password and timestamp: 2024-03-05"

What apply() Does

apply() works exactly like call(), but it takes arguments as array instead passing one by one.

Syntax:

function.apply(thisObject, [argument1, argument2, ...]);

Using apply()

let person = {
  name: "Frank",
  introduce: function(age, city) {
    console.log(this.name + " is " + age + " years old and lives in " + city);
  }
};

let person2 = {
  name: "Grace"
};

person.introduce.apply(person2, [28, "New York"]);
//"Grace is 28 years old and lives in New York"

Practical Use of apply()

apply() is perfect when you have arguments in an array:

let calculator = {
  add: function(a, b, c) {
    return a + b + c;
  }
};

let numbers = [5, 10, 15];

// apply() unpacks the array
let result = calculator.add.apply(null, numbers);
console.log(result); // Output: 30

What bind() Does

bind() creates a new function with this permanently attach to that obejct. Unlike call() and apply(), it doesn't run the function immediately.

Syntax:

let newFunction = function.bind(thisObject, argument1, argument2, ...);

Using bind()

let person = {
  name: "Henry",
  greet: function() {
    console.log("Hello, I'm " + this.name);
  }
};

let person2 = {
  name: "Ivy"
};

let greetIvy = person.greet.bind(person2);

greetIvy(); //"Hello, I'm Ivy"

greet() method is permanently bound to person2 object, so this always = person2

bind() for Storing Functions

let player = {
  name: "Jack",
  health: 100,
  takeDamage: function(damage) {
    this.health -= damage;
    console.log(this.name + " now has " + this.health + " health");
  }
};

let jackTakeDamage = player.takeDamage.bind(player);

setTimeout(jackTakeDamage, 1000, 10);
// After 1 second: "Jack now has 90 health"

bind() permanently ties the takeDamage() function to the player object, so this = player forever, no matter when or where it's called.

Comparison Table - call() vs apply() vs bind() vs Arrow Functions

Feature Regular Function Arrow Function call() apply() bind()
Has own this? Yes No Yes Yes Yes
this from where? Caller/Object Parent scope Controlled Controlled Controlled
Runs immediately? N/A N/A Yes Yes No
Arguments format Any Any Separate Array Separate
Works with call/apply/bind? ✅ Yes ❌ No

I hope this 😂 blog means my blog , help you to understand call(), apply() & bind() .

Happy Coding 👨‍💻!