Skip to main content

Command Palette

Search for a command to run...

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

Updated
7 min read
The Magic of this, call(), apply(), and bind() in JavaScript
N

I build clean and simple web experiences and learn something new every day.

If you’ve been learning JavaScript for a while, you’ve probably seen the keyword this and thought:

Wait… what exactly is this pointing to here?

And then later you discover call(), apply(), and bind() and things become even more confusing. But don’t worry. In this blog I’m going to explain everything step by step.

By the end of this post you’ll clearly understand:

  • what this really means

  • how functions decide what this refers to

  • how call(), apply(), and bind() let you control this manually

Let’s start from the very beginning.


What Does this Mean in JavaScript?

The easiest way to understand this is this simple idea this refers to the object that is calling the function. Not where the function was written. Not where it exists in the file. It depends on who is calling it.

Think about it like this imagine someone shouts:

Hey, introduce yourself!

Who should speak?
It depends on who was asked. JavaScript works in a similar way.


A Simple Rule That Helps a Lot

Most of the time you can use this rule - this is the object to the left of the dot when a function is called.

person.greet()
person.greet()

this = person

So inside greet(), the value of this will be person.


this Inside a Normal Function

Let’s look at a basic function and see how it works inside a normal function.

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

show();

Here the function is called without any object. So JavaScript doesn’t know who owns it. In browsers, this becomes the global object (window).

In strict mode it becomes undefined.

"use strict";

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

show(); // undefined

That’s why beginners sometimes get confused here. The function has no owner, so JavaScript uses the global context.


this Inside an Object

Now things start making more sense here.

const user = {
  name: "Nausheen",
  greet() {
    console.log(`Hello, I'm ${this.name}`);
  }
};

user.greet(); // Hello I'm Nausheen

Why?
because:

user.greet()

this = user

So this.name becomes "Nausheen"


When a Function Loses Its Context

Now watch something interesting here.

const user = {
  name: "Nausheen",
  greet() {
    console.log(`Hello, I'm ${this.name}`);
  }
};

const sayHello = user.greet;

sayHello(); // Hello, I'm undefined

Why?
Because now the function is called like this:

sayHello()

There is no object calling it anymore. So this lost its original context. And this exact problem is where call(), apply(), and bind() become useful.


Understanding the Function - Caller Relationship

You can imagine it like this:

Object ------ calls ------> Function

person.greet()

this = person

But if the function is called alone:

greet()

this = global / undefined

So sometimes we need a way to tell the function who its caller should be. That’s exactly what these methods do.


What call() Does

call() lets you run a function and manually set what this should be.

function introduce(city, hobby) {
  console.log(`I'm \({this.name} from \){city} and I like ${hobby}`);
}

const person = {
  name: "Aisha"
};

introduce.call(person, "Delhi", "reading");
I'm Aisha from Delhi and I like reading

Explanation:

introduce.call(person, "Delhi", "reading")

this = person
city = "Delhi"
hobby = "reading"

The function runs immediately. And the first argument always becomes this.


Method Borrowing Using call()

A very common use of call() is borrowing a method from another object.

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

const designer = {
  name: "Priya"
};

developer.introduce.call(designer);
Hi I'm Priya

Here we used developer's method for designer without copying the function.


What apply() Does

apply() works almost exactly like call(). The only difference is how arguments are passed.

call()

Arguments are passed one by one

function show(city, hobby) {}

show.call(user, "Mumbai", "coding");

apply()

Arguments are passed inside an array

function show(city, hobby) {}

show.apply(user, ["Mumbai", "coding"]);
function introduce(city, hobby) {
  console.log(`\({this.name} lives in \){city} and likes ${hobby}`);
}

const user = {
  name: "Kabir"
};

const details = ["Pune", "music"];

introduce.apply(user, details);
Kabir lives in Pune and likes music

So remember:

  • call - arguments separately

  • apply - arguments in an array


What bind() Does

bind() is a little different. Instead of running the function immediately, it returns a new function. And in that new function, this is permanently set.

function greet() {
  console.log(`Hello ${this.name}`);
}

const user = {
  name: "Sara"
};

const newGreet = greet.bind(user);

At this point nothing runs yet. newGreet is just a new function. Now when we call it:

newGreet(); // Hello Sara

And no matter where you call it later, this will always stay user.


Why bind() Is Useful

bind() is often used when passing functions around. For example in callbacks or timers.

const timer = {
  message: "Time finished",

  show() {
    console.log(this.message);
  },

  start() {
    setTimeout(this.show.bind(this), 2000);
  }
};

timer.start();

Without bind, this.message might become undefined. bind() keeps the correct object context.


call vs apply vs bind

Here’s the easiest way to compare them.

Feature call() apply() bind()
Executes immediately Yes Yes No
Returns Function result Function result New function
Arguments Passed one by one Passed as array Passed one by one
Main use Method borrowing When arguments are already in array Store function for later

Simple memory trick: call & apply run immediately, bind prepares a function for later


Small Practice Assignment

Try this small exercise to make the concept clear.

Step 1 Create an object

const developer = {
  name: "Arjun",
  language: "JavaScript",

  introduce() {
    console.log(`Hi I'm \({this.name} and I use \){this.language}`);
  }
};

Step 2 Create another object

const designer = {
  name: "Riya",
  language: "Figma"
};

Step 3 Borrow the method using call()

developer.introduce.call(designer);

Step 4 Use apply()

function showSkills(skill1, skill2) {
  console.log(`\({this.name} knows \){skill1} and ${skill2}`);
}

const skills = ["UI Design", "Prototyping"];

showSkills.apply(designer, skills);

Step 5 Use bind()

const devSkills = showSkills.bind(developer);

devSkills("React", "Node");

Try changing the objects and run the code yourself. That’s the best way to really understand how this behaves.


Final Thoughts

Once you understand one simple idea, everything becomes clear: this depends on who calls the function.

Then the rest becomes tools to control it.

  • call() => run the function immediately with a chosen this

  • apply() => same as call but arguments come as an array

  • bind() => create a new function with this permanently set

Whenever you feel confused, just ask yourself:

Who is calling this function right now?

If you answer that question, you’ll almost always know what this is. And once that clicks, these concepts stop feeling like magic and start feeling completely predictable.

More from this blog

C

codeXninjaDev

54 posts

I build clean and simple web experiences and learn something new every day.