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
S
A front-end developer who’s always learning, building projects, and writing blogs to simplify web concepts

What does this mean in JavaScript?

In the title, I used the phrase “The Magic of JavaScript.”
Of course, there is no real magic in programming; everything follows clear rules and logic.
But JavaScript has certain concepts that, at first glance, make you pause and think, “How did that just work?” That feeling is what I call magic.

One of the biggest examples of this “magic” is the this keyword.

Let's begin by exploring: What this is, what it means, and what it actually does.

In simple terms, this it points to the current context of a function.
More specifically, it refers to the object that is calling the function at that moment.

The value of this It is not fixed. It changes based on how and where a function is called.
This behavior is what often confuses beginners and makes this them feel mysterious.

Let's start with an example for better understanding:-

const userLogin = {
  username: "zemong",
  uid: 131331,
  welcomeMsg: function () {
    console.log(`${this.username},welcome to the game`);
  },
};
userLogin.welcomeMsg(); //output zemong,welcome to the game

userLogin.username = "soumyaditya";

userLogin.welcomeMsg();//output soumyaditya,welcome to the game

Let’s imagine we are building a game login page.
Whenever a user logs into the game, the system should display a welcome message with the player’s username.

To do this, we create an object called userLogin.
This object represents the currently logged-in user and contains:

  • username → the player’s name

  • uid → the user’s unique ID

  • welcomeMsg() → a method that prints a welcome message

Inside the welcomeMsg method, we use:

this.username

Why not just hardcode the username as "zemong"?

Hardcoding the username is not a good practice because:

Hardcoding the username is not advisable because a game can have many users, usernames change with each login, and developers cannot manually update the username for every login.

That’s why we use this.username.Here, this refers to the object that is calling the method.
In this case, userLogin.welcomeMsg() is calling the function, so this points to the entire userLogin object.

When JavaScript sees this.username, it:

  1. Checks who is calling the function (userLogin)

  2. Uses that object as the context

  3. Reads the username value from it

  4. Prints the correct welcome message

The first call prints “zemong, welcome to the game,” and after updating the username, the second call prints “soumyaditya, welcome to the game.”

Think of this as a chameleon. Just as a chameleon changes color based on its environment, turning green on a leaf and rocky on a stone, this changes its value depending on the context in which a function is called. It doesn't have a fixed meaning on its own but adapts to its surroundings, pointing to the current caller. Wherever the function is executed, this refers to that scope or object and retrieves values from there. In our game login example, when welcomeMsg() is called using userLogin.welcomeMsg(), this points to the userLogin object, allowing thisusername to automatically get the username of the player who is logged in.

That’s why, in different environments, logging this gives different results. When you console.log(this) are in a Node.js environment, it usually prints an empty object ({}) because Node treats each file as its own module, and this at the top level refers to module.exports. On the other hand, when you log this in a browser console, it prints the window object, because in browsers, the global context is the window. This difference again proves that this it does not have a fixed value. It always depends on where the code is running and who is calling it.

What call() does

Once we understand what this is and what the this keyword does, we can look at call(), apply(), and bind(), starting with call(). These methods aren't used often in beginner code, but they're important because they control the value of this, making them powerful.

Before we dive into call(), we know how JavaScript runs code. Everything goes through the call stack, where functions run one by one. When a function is called, it's added to the stack; once it finishes, it's removed.

For example lets take a function that calls another function inside it. The outer function runs first, then the inner one. What does this point to in the inner function? Since the outer function is done and the inner function is called normally, this falls back to the global context. This can confuse developers, but call() helps by letting us define what this should point to.

Now lets understand call() with an example :-

function gameName(username) {
  // DB call like if this username alrady exist return something else return the username
  this.username = username;
}

function creatUserInfo(username, uid, rank) {
  gameName(username);
  this.uid = uid;
  this.rank = rank;
}

const oneUser = new creatUserInfo("zemong", "44405052", "gold");
console.log(oneUser);

At first glance, this code looks correct.
We have a gameName A function that takes a username and assigns it using this.username. Then we have another function, creatUserInfo, which takes three parameters: username, uid, and rank. Inside this function, we call gameName(username) and then assign uid rank to this. Finally, we create a new user object using the new keyword and log it.

However, when we run this code, the output is:

creatUserInfo { uid: '44405052', rank: 'gold' }

Why does this happen?

When we use the new keyword with creatUserInfoJavaScript creates a new object, and inside creatUserInfo, this correctly refers to that new object. That’s why this.uid and this.rank work as expected.

But the problem is this line:

gameName(username);

In gameName, the function is called normally, not as an object method. So, this inside gameName doesn't point to the new object. Instead, it defaults to the global context (or undefined in strict mode). Therefore, this.username isn't added to the oneUser object.

So even though gameName runs, it does not modify the object we actually care about.

How does call() fix this?
call() allows us to manually set what this should refer to when calling a function.

function creatUserInfo(username, uid, rank) {
  gameName.call(this, username);
  this.uid = uid;
  this.rank = rank;
}

Now, when gameName runs:

  • this inside gameName refers to the same object created by new creatUserInfo()

  • this.username is correctly assigned to that object

So the final output becomes:

creatUserInfo {
  username: 'zemong',
  uid: '44405052',
  rank: 'gold'
}

In simple words, call() let's one object use another object’s function by telling JavaScript what this should be. It helps us reuse the same function for different objects without writing the code again.

Understanding apply() in JavaScript

The apply() method exists for the same purpose as call()to control what this points tobut it solves a slightly different problem. The difference is not in what it does, but in how data is passed to the function.

Using the same game login example:

function gameName(username) {
  this.username = username;
}

function createUserInfo(username, uid, rank) {
  gameName.apply(this, [username]);
  this.uid = uid;
  this.rank = rank;
}

const oneUser = new createUserInfo("zemong", "44405052", "gold");
console.log(oneUser);

Here, apply() sets the value of this inside gameName to the newly created user object—just like call() does. The important difference is that arguments are passed as a single array instead of individual values.

This makes apply() especially useful when:

  • The arguments are already stored in an array

  • The number of arguments is dynamic or unknown

  • You want to forward values without unpacking them manually

So instead of writing arguments one by one, apply() allows the function to receive them directly from an array while still keeping this correctly bound.

What bind() does

The bind() method is different from call() and apply() in one important way:
it does not execute the function immediately.

Instead, bind() creates a new function where the value of this is permanently fixed. You can call that function later whenever you want, and this will still point to the same object.

Using the same game login example:

function gameName(username) {
  this.username = username;
}

function createUserInfo(username, uid, rank) {
  const setUsername = gameName.bind(this, username);
  setUsername();
  this.uid = uid;
  this.rank = rank;
}

const oneUser = new createUserInfo("zemong", "44405052", "gold");
console.log(oneUser);

Here, bind() does not run gameName right away. Instead, it returns a new function (setUsername) with this already bound to the newly created user object. When we later call setUsername(), this.username is correctly assigned.

This makes bind() especially useful when:

  • You want to store a function and call it later

  • You need to pass a function as a callback

  • You want this to stay the same no matter how or where the function is called

Key difference between call( ) , apply( ) and bind ( )

  • call() =>runs the function immediately

  • apply() => runs the function immediately

  • bind() =>returns a new function to run later

In short, bind() is about preserving context for future use, not immediate execution.

Conclusion

Understanding this, call(), apply(), and bind() removes one of the biggest sources of confusion in JavaScript. There is no real “magic” here—only context. The this keyword simply refers to who is calling the function, and its value changes depending on how and where the function is executed.

When normal function calls are not enough, call() and apply() give us control by letting us explicitly decide what this should point to, making function reuse possible across different objects. bind(), on the other hand, locks the context permanently and lets us use the function later without worrying about losing this.

JavaScript Journey: From Basics to Core Concepts

Part 3 of 29

This series documents my journey of learning JavaScript and breaking down important concepts in a simple way. Each article covers a core JavaScript topic with clear explanations and beginner-friendly examples. From basic concepts to essential JavaScript features, the goal of this series is to make JavaScript easier to understand while practicing and sharing what I learn.

Up next

Life, Commitments, and JavaScript Promises

Turns out your life already understands async programming