Skip to main content

Command Palette

Search for a command to run...

Understanding this, call(), apply(), and bind() in JavaScript

Updated
7 min read
Understanding this, call(), apply(), and bind() in JavaScript
H
CS undergrad | Tech enthusiast | Focusing on Web Dev • DSA • ML | Building skills for real-world impact

If you've ever stared at the word this in JavaScript and had no idea what it was referring to — you're not alone. It's one of the most confusing parts of the language for beginners. But once you crack it, everything starts to make sense.

Let's break it down simply, with examples you can run right in your browser console.


What Is this?

Here's the simplest way to think about it:

this refers to whoever is calling the function.

It's not about where the function was written. It's about who triggered it at the moment it runs.

Think of a function like a worker. this is the worker asking: "Who hired me right now? I'll work for them."

[ Function ]
     ↑
     | "Who called me?"
     |
[ The Caller ] ← this = the caller

this Inside Normal Functions

When you call a function on its own (not attached to an object), this refers to the global object — which is window in a browser.

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

greet(); // logs the window object (in a browser)

In strict mode, this inside a standalone function is undefined instead.

"use strict";

function greet() {
  console.log(this); // undefined
}

greet();

Takeaway: Standalone functions have unpredictable this. The magic happens when functions are attached to objects.


this Inside Objects

When a function lives inside an object and is called through that object, this refers to that object.

const user = {
  name: "Sarah",
  greet: function () {
    console.log("Hello, my name is " + this.name);
  },
};

user.greet(); // "Hello, my name is Sarah"

Here, user is calling greet(), so this is user. Simple!

Now what if we try to borrow that function?

const greetFn = user.greet;
greetFn(); // "Hello, my name is undefined" ⚠️

The function lost its connection to user. It's no longer being called through an object, so this no longer knows who it belongs to.

This is exactly the problem that call(), apply(), and bind() solve.


call() — Borrow a Function and Run It Now

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

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

const person = { name: "Carlos" };

introduce.call(person, "Madrid", "Spain");
// "I'm Carlos from Madrid, Spain."

Syntax:

functionName.call(thisValue, arg1, arg2, ...)

You pass the object you want as this first, then the arguments one by one.

Borrowing a method between objects

const dog = {
  name: "Buddy",
  describe: function () {
    console.log(this.name + " is a good dog.");
  },
};

const cat = { name: "Whiskers" };

dog.describe.call(cat); // "Whiskers is a good dog."

cat borrowed dog's method using call(). The function ran as if it belonged to cat.


apply() — Like call(), but Arguments Go in an Array

apply() works exactly like call(), with one difference: you pass arguments as an array instead of one by one.

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

const person = { name: "Aisha" };
const details = ["Lagos", "Nigeria"];

introduce.apply(person, details);
// "I'm Aisha from Lagos, Nigeria."

Syntax:

functionName.apply(thisValue, [arg1, arg2, ...])

When is apply() useful?

When your arguments are already in an array — like data coming from an API or user input — apply() saves you from spreading them manually.

const numbers = [3, 7, 1, 9, 4];
console.log(Math.max.apply(null, numbers)); // 9

(We pass null here because Math.max doesn't use this.)


bind() — Create a New Function with this Locked In

Unlike call() and apply(), bind() does not run the function immediately. Instead, it returns a brand new function where this is permanently set to whatever you choose.

function greet() {
  console.log("Hello, I'm " + this.name);
}

const player = { name: "Jordan" };

const greetJordan = greet.bind(player);

// Nothing ran yet. We stored the bound function.

greetJordan(); // "Hello, I'm Jordan"
greetJordan(); // "Hello, I'm Jordan" (still works later)

Syntax:

const newFn = functionName.bind(thisValue, arg1, arg2, ...)

Why is bind() useful?

It's especially handy when passing methods as callbacks, where the original this would otherwise be lost.

const timer = {
  message: "Time's up!",
  start: function () {
    setTimeout(this.ring.bind(this), 1000);
  },
  ring: function () {
    console.log(this.message);
  },
};

timer.start(); // "Time's up!" (after 1 second)

Without bind(this), the setTimeout callback would lose the reference to timer.


call vs apply vs bind — Side by Side

Feature call() apply() bind()
Runs immediately? Yes Yes No — returns a new function
How args are passed One by one As an array [ ] One by one (at bind time or call time)
Returns The function's result The function's result A new bound function
Best used when You want to run it now with specific args Your args are already in an array You want to save it and call it later

Putting It All Together

const doctor = {
  name: "Dr. Patel",
  diagnose: function (symptom, severity) {
    console.log(`\({this.name} says: \){symptom} is ${severity}.`);
  },
};

const nurse = { name: "Nurse Kim" };

// call() — run now, pass args one by one
doctor.diagnose.call(nurse, "fever", "mild");
// "Nurse Kim says: fever is mild."

// apply() — run now, pass args as array
doctor.diagnose.apply(nurse, ["headache", "moderate"]);
// "Nurse Kim says: headache is moderate."

// bind() — save for later
const nurseCheck = doctor.diagnose.bind(nurse);
nurseCheck("fatigue", "severe");
// "Nurse Kim says: fatigue is severe."

Practice Assignment

Work through these steps to solidify the concepts:

1. Create an object with a method using this:

const car = {
  brand: "Toyota",
  describe: function () {
    console.log("This car is a " + this.brand);
  },
};

car.describe(); // works as expected

2. Borrow that method using call():

const bike = { brand: "Yamaha" };

car.describe.call(bike); // "This car is a Yamaha"

3. Use apply() with array arguments:

function showDetails(year, color) {
  console.log(`\({this.brand} — \){year} — ${color}`);
}

const details = [2022, "red"];
showDetails.apply(car, details);  // "Toyota — 2022 — red"
showDetails.apply(bike, details); // "Yamaha — 2022 — red"

4. Use bind() and store the function:

const describeBike = car.describe.bind(bike);

// Call it whenever you need
describeBike(); // "This car is a Yamaha"
describeBike(); // still works!

Quick Recap

  • this always refers to whoever is calling the function at runtime

  • Inside objects, this is the object itself

  • Standalone functions can lose this — that's where the three methods come in

  • call() — runs immediately, arguments passed one by one

  • apply() — runs immediately, arguments passed as an array

  • bind() — doesn't run immediately, returns a new function with this locked in

Master these three and you'll never feel confused by this again.

Happy coding! 🚀


If you enjoyed this article, check out my other blogs on this profile.

🔗 Connect with me:
LinkedIn | GitHub | X (Twitter)