Understanding `this`, call(), apply(), and bind() in JavaScript
Who's calling the function? A beginner-friendly guide to JavaScript's most confusing keyword

If you've been following along in this series, you already know how functions, arrays, and objects work in JavaScript. Today we're tackling something that trips up almost every beginner (and honestly, a few experienced devs too): the keyword this.
By the end of this article, you'll understand this, and you'll also know how to control it using three handy methods: call(), apply(), and bind().
1. What Does this Mean in JavaScript? (Simple Explanation)
Here's the simplest way to think about this:
thismeans "who is calling the function."
That's it. this isn't about where a function is written - it's about who calls it.
Think of it like a phone call. If your mom calls you, you say "Hi Mom." If your friend calls you, you say "Hi [friend's name]." You (the function) haven't changed - but how you respond depends on who's on the other end of the call.
function greet() {
console.log("Hello, " + this.name);
}
Right now, this function doesn't know who this is. It depends entirely on how greet() gets called. Let's see that in action.
2. this Inside Normal Functions
When you call a normal function on its own (not attached to any object), this doesn't point to anything useful for beginners - it points to the global object (or undefined in strict mode).
function whoIsThis() {
console.log(this);
}
whoIsThis();
// Output: behaviour of this in different environment
// In a browser: logs the "window" object
// In strict mode: logs "undefined"
Why? Because nobody meaningful is "calling" this function - it's just being called directly, with no object in front of it.
function sayHi() {
console.log("Hi, I am " + this.name);
}
sayHi(); // "Hi, I am undefined"
// because `this` isn't pointing to any object with a "name"
At this stage, just remember: a plain function call has no clear "caller," so
thisisn't useful yet. That changes as soon as we attach the function to an object.
3. this Inside Objects
This is where this starts to make sense. When a function is a method (a function stored inside an object) and you call it through that object, this refers to the object doing the calling.
const user = {
name: "Sahil",
greet: function () {
console.log("Hello, I am " + this.name);
}
};
user.greet(); // "Hello, I am Sahil"
Here's the key moment:
user.greet()- the objectuseris standing right before the dot when we call the function. That makesuserthe "caller," sothisbecomesuser.
Before / After: Same Function, Different Caller
const student = {
name: "Riya",
greet: function () {
console.log("Hi, I'm " + this.name);
}
};
const teacher = {
name: "Meera",
greet: student.greet // borrowing the same function!
};
student.greet(); // "Hi, I'm Riya"
teacher.greet(); // "Hi, I'm Meera"
Same function. Same code. Two different outputs - because the caller changed. This is the whole idea of this in one example.
4. What Does call() Do?
call() lets you run a function and manually decide what this should be - even if the function doesn't naturally belong to that object.
function greet() {
console.log("Hello, I am " + this.name);
}
const person = { name: "Aman" };
greet.call(person); // "Hello, I am Aman"
Here, greet was never attached to person. But call() says: "Run greet(), and pretend person is the one calling it."
You can also pass arguments after the object, one by one:
function introduce(city, hobby) {
console.log(`I am ${this.name} from ${city}. I love ${hobby}.`);
}
const person = { name: "Aman" };
introduce.call(person, "Mumbai", "cricket"); // "I am Aman from Mumbai. I love cricket."
5. What Does apply() Do?
apply() does the exact same job as call() - the only difference is how you pass arguments. Instead of listing them one by one, you pass them as an array.
function introduce(city, hobby) {
console.log(`I am ${this.name} from ${city}. I love ${hobby}.`);
}
const person = { name: "Aman" };
introduce.apply(person, ["Mumbai", "cricket"]); // "I am Aman from Mumbai. I love cricket."
Notice: same result as
call(), but the arguments["Mumbai", "cricket"]are packed into one array instead of being written separately.
Handy real-world use: apply() is great when you already have your data sitting in an array and don't want to unpack it manually.
6. What Does bind() Do?
call() and apply() run the function immediately. bind() is different - it doesn't run the function right away. Instead, it gives you back a new function, permanently linked to the this you chose, which you can call whenever you want.
function greet() {
console.log("Hello, I am " + this.name);
}
const person = { name: "Aman" };
const boundGreet = greet.bind(person);
boundGreet(); // "Hello, I am Aman" — runs whenever YOU decide to call it
Think of bind() as pre-setting the caller and saving the function for later - like saving a contact in your phone so you don't have to dial the number every time.
function introduce(city) {
console.log(`I am ${this.name} from ${city}.`);
}
const person = { name: "Aman" };
const introduceAman = introduce.bind(person, "Mumbai");
introduceAman(); // "I am Aman from Mumbai."
7. Difference Between call, apply, and bind
| Feature | call() |
apply() |
bind() |
|---|---|---|---|
| Runs the function immediately? | Yes | Yes | No - returns a new function |
| How arguments are passed | One by one | As an array | One by one (can be partial) |
| Returns | The function's result | The function's result | A new function |
| Best used when | You have a few known arguments | Your arguments are already in an array | You want to use the function later |
Quick Way to Remember
call - comma-separated arguments
apply - array of arguments
bind - be used later (doesn't run immediately)
Diagram: Function → Caller Relationship
The pattern is always the same: find who's standing before the function when it's called - that's
this.
Assignment: Practice this, call(), apply(), and bind()
Try this on your own before checking the solution:
Create an object
studentwith anameand a methodintroducethat usesthis.name.Create a plain object
otherStudent(just aname, no method).Borrow
student.introduceand run it onotherStudentusingcall().Run the same method on
otherStudentusingapply(), passing arguments as an array.Use
bind()to create a new function tied tootherStudent, store it in a variable, and call it separately.
Click to see the solution
const student = {
name: "Sahil",
introduce: function (city, hobby) {
console.log(`I am ${this.name} from ${city}. I love ${hobby}.`);
}
};
const otherStudent = { name: "Priya" };
// Using call()
student.introduce.call(otherStudent, "Delhi", "reading"); // "I am Priya from Delhi. I love reading."
// Using apply()
student.introduce.apply(otherStudent, ["Delhi", "reading"]); // "I am Priya from Delhi. I love reading."
// Using bind()
const introducePriya = student.introduce.bind(otherStudent, "Delhi", "reading");
introducePriya(); // "I am Priya from Delhi. I love reading."
Wrapping Up
this isn't magic - it's just a question: "Who called this function?" Once you start asking that question every time you see this in code, it stops being confusing.
Plain function call -
thisisn't useful (global or undefined)Called through an object -
thisis that objectcall()/apply()- you choosethisand run immediatelybind()- you choosethisand save it for later
If you found this useful, drop a comment or a reaction.




