Skip to main content

Command Palette

Search for a command to run...

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

Published
6 min read
The Magic of this, call(), apply(), and bind() in JavaScript

There is a keyword in JavaScript that confuses almost every beginner the first time they run into it. That keyword is this. It shows up everywhere, it behaves differently depending on where it is used, and the error messages it produces when something goes wrong are not always the most helpful.

Once we understand this properly though, and once we see how call(), apply(), and bind() work alongside it, a lot of JavaScript code that previously looked confusing starts to make complete sense.


What Does this Mean?

The simplest way to think about this is this: it refers to whoever is calling the function at that moment.

It is not fixed. It does not always point to the same thing. It changes based on the context in which a function is called. That is what makes it tricky at first, but also what makes it powerful once we get the hang of it.

Let's start with the most common place we see this, inside an object.


this Inside an Object

When a function is defined inside an object and called on that object, this refers to that object.

let student = {
  name: "Gurjeet",
  age: 22,
  introduce: function() {
    console.log("My name is " + this.name + " and I am " + this.age + " years old");
  }
};

student.introduce();
// My name is Gurjeet and I am 22 years old

When we call student.introduce(), JavaScript sets this to student because student is the one calling the function. So this.namebecomes student.name, which is "Gurjeet".

Now let's create another object and see what happens:

let teacher = {
  name: "Mr. Singh",
  age: 35,
  introduce: function() {
    console.log("My name is " + this.name + " and I am " + this.age + " years old");
  }
};

teacher.introduce();
// My name is Mr. Singh and I am 35 years old

Same function structure, different object, different result. this adapts to whoever is calling it. That is the core behaviour to understand.


The Problem this Creates

Here is where things get interesting. What if we have a function on one object but we want to use it on a different object that does not have that function?

let student = {
  name: "Gurjeet",
  age: 22,
  introduce: function() {
    console.log("My name is " + this.name + " and I am " + this.age);
  }
};

let anotherStudent = {
  name: "Priya",
  age: 21
};

anotherStudent does not have an introduce method. We could copy the function over, but that is repetitive and messy. This is exactly the problem that call(), apply(), and bind() solve.


call()

call() lets us borrow a function from one object and use it on another. We call the function and explicitly tell JavaScript what this should be.

student.introduce.call(anotherStudent);
// My name is Priya and I am 21

We took the introduce function from student and called it with anotherStudent as the context. JavaScript set this to anotherStudentfor that call, so this.name became "Priya" and this.age became 21.

We can also pass additional arguments after the object:

let student = {
  name: "Gurjeet",
  greet: function(city, course) {
    console.log("Hi, I am " + this.name + " from " + city + ", studying " + course);
  }
};

let anotherStudent = { name: "Priya" };

student.greet.call(anotherStudent, "Delhi", "Design");
// Hi, I am Priya from Delhi, studying Design

The first argument to call() is always the object we want this to be. Everything after that gets passed as regular arguments to the function.


apply()

apply() works exactly like call(). The only difference is how we pass the arguments. With call() we pass them one by one. With apply() we pass them as an array.

student.greet.apply(anotherStudent, ["Delhi", "Design"]);
// Hi, I am Priya from Delhi, studying Design

Same result as before. The difference is purely in the syntax. call() takes individual arguments separated by commas. apply()takes a single array containing all the arguments.

A practical way to remember this: call uses commas, apply uses an array.

When would we actually use apply() over call()? When our arguments are already sitting in an array and we do not want to unpack them manually.

let args = ["Mumbai", "Full Stack Development"];

student.greet.apply(anotherStudent, args);
// Hi, I am Priya from Mumbai, studying Full Stack Development

bind()

bind() is a little different from call() and apply(). Instead of calling the function immediately, bind() returns a new function with this permanently set to whatever we specify. We can then call that new function whenever we want.

let student = {
  name: "Gurjeet",
  introduce: function() {
    console.log("My name is " + this.name);
  }
};

let anotherStudent = { name: "Priya" };

let priyanIntroduce = student.introduce.bind(anotherStudent);

priyanIntroduce();
// My name is Priya

We used bind() to create a new function called priyanIntroduce where this is permanently set to anotherStudent. Now we can call priyanIntroduce() anywhere in our code and it will always use anotherStudent as the context.

This is useful when we want to pass a function around, store it for later use, or use it as a callback, but we need to make sure it always runs with the right this.


call vs apply vs bind

All three let us control what this is inside a function. The difference is in how and when they execute:

call() runs the function immediately and accepts arguments one by one.

apply() runs the function immediately and accepts arguments as an array.

bind() does not run the function immediately. It returns a new function with this locked in, ready to be called later.

let person = {
  name: "Gurjeet",
  sayHello: function(greeting, punctuation) {
    console.log(greeting + ", I am " + this.name + punctuation);
  }
};

let anotherPerson = { name: "Priya" };

// call — runs immediately, arguments one by one
person.sayHello.call(anotherPerson, "Hello", "!");
// Hello, I am Priya!

// apply — runs immediately, arguments as array
person.sayHello.apply(anotherPerson, ["Hey", "."]);
// Hey, I am Priya.

// bind — returns new function, call it later
let boundFn = person.sayHello.bind(anotherPerson, "Hi", "...");
boundFn();
// Hi, I am Priya...

Why This Actually Matters

At first glance, call(), apply(), and bind() might feel like edge case tools. But they show up regularly in real JavaScript development. Borrowing methods between objects, setting the correct context for event handlers, working with callbacks, all of these situations involve controlling what this points to.

Understanding this and having these three tools in our toolkit means we are no longer guessing why a function is returning undefined for a property that clearly exists. We know exactly what this is, and we know how to change it when we need to.

Javascript

Part 3 of 10

A beginner-friendly series covering the core concepts of JavaScript from the ground up. Each post breaks down one topic at a time using simple language, real-world analogies, and practical code examples. Whether we are just starting out or looking to solidify the basics, this series covers everything from variables and data types to object-oriented programming.

Up next

JavaScript Arrays 101

Let's say we want to store the names of five students in our program. Without arrays, we would do something like this: let student1 = "Gurjeet"; let student2 = "Priya"; let student3 = "Rahul"; let stu