DEV Community

Cover image for The Magic of `this`, `call()`, `apply()`, and `bind()` in JavaScript
Subhrangsu Bera
Subhrangsu Bera

Posted on

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

Have you ever been in a conversation where someone said, "This is amazing!" and you had to ask, "Wait, what exactly is 'this'?" In JavaScript, the this keyword faces the same identity crisis. It is a placeholder that changes its meaning depending on who is speaking.

If you can master the simple rule of "Who is calling the function?", you will master the most confusing part of the language.

1. What does this actually mean?

In the simplest terms: this refers to the object that is currently executing the code.

Think of it like a person's name tag. If I wear the tag, this refers to me. If you wear it, this refers to you. The tag doesn't change, but the person wearing it does.

this inside a Normal Function

If a function is called by itself, this does not belong to any object.
In browsers it usually refers to the global object (window), but in strict mode it becomes undefine

function showThis() {
    console.log(this); // Logs the Window object
}
showThis();
Enter fullscreen mode Exit fullscreen mode

this inside an Object (The Home Owner)

When a function lives inside an object, we call it a Method. Here, this is very happy because it knows exactly who its owner is: the object it lives in.

const student = {
    name: "Veer",
    greet() {
        console.log("Hi, I am " + this.name);
    },
};

student.greet(); // Output: Hi, I am Veer
Enter fullscreen mode Exit fullscreen mode

Since student called the function, this.name becomes student.name.

Function → Caller relationship diagram

2. Hijacking the Context: Method Borrowing

Sometimes, a chef has a great recipe (a method), and another chef wants to use it without rewriting it. JavaScript gives us three "magic" tools to change who this refers to, effectively allowing one object to borrow a method from another.

Tool 1: call()

The call() method runs a function and explicitly tells it: "Forget your usual owner; for this one time, this object is your boss." You pass arguments one by one.

const person1 = {
    name: "Ansh",
    greet() {
        console.log("Hello, I am " + this.name);
    },
};

const person2 = {
    name: "Ravi",
};

person1.greet.call(person2);
Enter fullscreen mode Exit fullscreen mode

Output:

Hello, I am Ravi
Enter fullscreen mode Exit fullscreen mode

Tool 2: apply()

apply() is the twin sibling of call(). It does the exact same thing, but it’s a bit more organized. Instead of passing arguments one by one, it expects them in a single Array.

function introduce(city, country) {
    console.log(`${this.name} from ${city}, ${country}`);
}

const user = { name: "Ravi" };

introduce.apply(user, ["Mumbai", "India"]);
Enter fullscreen mode Exit fullscreen mode

Output:

Ravi from Mumbai, India
Enter fullscreen mode Exit fullscreen mode

Tool 3: bind() - The "Save for Later" Button

bind() is fundamentally different. It doesn't run the function immediately. Instead, bind() creates a new function with this permanently set to the object you provide.

It’s like recording a recipe and handing the tape to a specific chef to use whenever they want.

const student = { name: "Veer" };

function study(subject) {
    console.log(`${this.name} is studying ${subject}`);
}

// This doesn't run the function yet! It creates a new one.
const veerStudies = study.bind(student);

// Later in your code...
veerStudies("JavaScript"); // Output: Veer is studying JavaScript
Enter fullscreen mode Exit fullscreen mode

3. The Comparison Table

Method Runs Immediately? Arguments Best Use
call() Yes call(obj, arg1, arg2) When arguments are known individually
apply() Yes apply(obj, [arg1, arg2]) When arguments are in an array
bind() No bind(obj) When you want to run the function later

Comarisson

4. Why does this matter? (The Practical Side)

You might be wondering, "Why not just write a new function?" 1. DRY (Don't Repeat Yourself): You can write complex logic once and apply it to many different data objects. 2. Callbacks: When you pass a method into something like a setTimeout or an event listener, JavaScript often "loses" the original this. bind() allows you to "tether" the function so it doesn't get lost.

5. Summary Challenge: The "Method Hijack"

Try this in your browser console to see the magic in real-time:

  1. Create a teacher object with a subject property and a method that says "I teach [subject]".
  2. Create a student object with a subject property but no method.
  3. Use teacher.teach.call(student) to make the student "borrow" the teacher's ability to speak.
  4. Notice how the student now talks about their subject using the teacher's code!

Mastering this is the gateway to advanced JavaScript. By understanding that the "owner" is decided at the moment of the call, you gain the power to write flexible, reusable, and professional-grade code.

Top comments (0)