Skip to main content
Madhukar
All Articles

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

August 14, 20267 min read
Interview PrepProgrammingJavaScriptWeb DevelopmentBeginner
The Magic of this, call(), apply(), and bind() in JavaScript

this = whoever is calling the function, right now

this is one of the most confusing words in JavaScript — not because the concept is complicated, but because its value changes depending on how a function is called, not where it was written. The simplest, most reliable way to think about it: this refers to whoever is calling the function, at the moment it's actually called. Once that framing clicks, call(), apply(), and bind() stop feeling like separate, unrelated tools — they're really just three different ways of controlling exactly who gets to be this.

What this Means in JavaScript (Simple Explanation)

Forget internal execution contexts for now — here’s the practical version: ask “who called this function?”, and that’s what this refers to inside it.

function whoAmI() {
console.log(this);
}

whoAmI(); // called with no specific object — this refers to the global object (or undefined in strict mode)

this Inside Normal Functions

When a regular function is called on its own — not attached to any object — this doesn't point to anything meaningful tied to your code:

function sayHello() {
console.log(this);
}

sayHello();
// In non-strict mode: the global object
// In strict mode: undefined

Nobody “owns” this call — it’s just sayHello(), called directly — so this defaults to something generic (or undefined in strict mode), rather than anything useful.

this Inside Objects

this becomes genuinely useful the moment a function is called as a method of an object — because now there's a clear, real "caller" to point to.

const person = {
name: "Aarav",
greet() {
console.log(`Hi, I'm ${this.name}`);
},
};

person.greet(); // "Hi, I'm Aarav"

Here, person.greet() is called on person — so this refers to person, and this.name correctly resolves to "Aarav".

The exact same function, called differently, behaves differently

const another = { name: "Priya" };
another.greet = person.greet;

another.greet(); // "Hi, I'm Priya" — same function, different caller, different this

This is the single most important thing to internalize: this isn't fixed to where a function was defined — it depends entirely on how it's actually called, each time.

What call() Does

call() lets you invoke a function while explicitly specifying what this should be — passing arguments individually, one at a time.

function greet() {
console.log(`Hi, I'm ${this.name}`);
}

const person1 = { name: "Aarav" };
const person2 = { name: "Priya" };

greet.call(person1); // "Hi, I'm Aarav"
greet.call(person2); // "Hi, I'm Priya"

greet isn't a method of either object — but call() lets you borrow it, telling JavaScript exactly which object this should refer to for that specific call.

call() with arguments

function greet(greeting) {
console.log(`${greeting}, I'm ${this.name}`);
}

greet.call(person1, "Hello"); // "Hello, I'm Aarav"

Additional arguments after the this value are passed to the function normally, one at a time.

What apply() Does

apply() does exactly the same job as call() — the only difference is how arguments are passed: as a single array, instead of individually.

function greet(greeting, punctuation) {
console.log(`${greeting}, I'm ${this.name}${punctuation}`);
}

greet.apply(person1, ["Hello", "!"]); // "Hello, I'm Aarav!"

Compare directly with call():

greet.call(person1, "Hello", "!");   // arguments listed individually
greet.apply(person1, ["Hello", "!"]); // arguments bundled into an array

apply() is especially useful when you already have your arguments sitting in an array, and don't want to manually unpack them one by one.

What bind() Does

bind() is different from both call() and apply() in one key way: instead of calling the function immediately, it returns a new function, permanently tied to whatever this you specify — ready to be called later, as many times as needed.

function greet() {
console.log(`Hi, I'm ${this.name}`);
}

const greetAarav = greet.bind(person1);

greetAarav(); // "Hi, I'm Aarav"
greetAarav(); // "Hi, I'm Aarav" — still Aarav, every time

Unlike call() and apply(), which run the function right away, bind() hands you back a stored, reusable function — extremely useful when you need to pass a function somewhere else (like an event handler) while making sure it still uses the correct this, no matter how or when it eventually gets called.

const button = { label: "Submit" };

function handleClick() {
console.log(`${this.label} was clicked`);
}

const boundHandler = handleClick.bind(button);
// Can be passed anywhere and called later — still correctly uses `button` as this
boundHandler(); // "Submit was clicked"

Difference Between call, apply, and bind

A simple way to remember it: “C” call and “A” apply both run immediately — they just differ in how arguments are shaped. “B” bind builds something for later, rather than running anything right away.

Practice Assignment

1. Create an object with a method using this

const student = {
name: "Meera",
introduce() {
console.log(`Hi, I'm ${this.name}`);
},
};

student.introduce(); // "Hi, I'm Meera"

2. Borrow that method using call()

const anotherStudent = { name: "Rohan" };

student.introduce.call(anotherStudent); // "Hi, I'm Rohan"

3. Use apply() with array arguments

function introduceWithCourse(course, year) {
console.log(`Hi, I'm ${this.name}, studying ${course}, year ${year}`);
}

introduceWithCourse.apply(anotherStudent, ["Computer Science", 2]);
// "Hi, I'm Rohan, studying Computer Science, year 2"

4. Use bind() and store the function

const boundIntro = introduceWithCourse.bind(anotherStudent, "Web Development");

boundIntro(3); // "Hi, I'm Rohan, studying Web Development, year 3"
boundIntro(4); // "Hi, I'm Rohan, studying Web Development, year 4"

Notice bind() can also pre-fill some arguments ("Web Development" here) while leaving others (year) to be supplied later, when the bound function is actually called.

Final Takeaway

this isn't mysterious once you stop asking "what does this mean here in the code" and start asking "who is calling this function, right now?" call() and apply() let you answer that question explicitly and run the function immediately — differing only in how they accept arguments. bind() answers it once and hands you back a new function that remembers the answer permanently, ready to be called whenever and however you need it later. All three exist to solve the exact same underlying problem: giving you deliberate control over this, instead of leaving it to be decided implicitly by how a function happens to get called.

Frequently Asked Questions

Why would I ever need to manually set this with call, apply, or bind?

> Whenever a function needs to run with a specific object as this, but isn't naturally being called as that object's own method — like borrowing a method from one object for use with another, or passing a function as a callback where it would otherwise lose its intended this.

Does arrow function syntax affect how this works?

> Yes, in a specific and different way — arrow functions don’t have their own this at all; they use this from the surrounding code where they were defined, regardless of how they're called. This is a deliberately different behavior worth learning as its own topic once regular function this behavior feels comfortable.

Can I use call, apply, or bind on any function?

> Yes — they work on any regular function. They’re commonly used specifically for borrowing methods between objects, or for controlling this when passing functions around as callbacks or event handlers.

Is bind() the same as just calling a function later?

> Not quite — simply storing a reference to a method and calling it later can lose its original this (as shown in the another.greet = person.greet example). bind() specifically locks in this permanently for that new function, regardless of how it's later invoked.

Originally published by Mr Madhukar

Read the complete article on Medium with full formatting & reader responses.