this, call, apply, and bind – Notes (The Topic That Made Me Question Everything I Knew About Functions)
Okay I'm going to be upfront about something. This topic took me longer to understand than anything else we've covered so far. Not because it's complicated exactly but because this in JavaScript behaves in a way that feels almost deliberately confusing when you first meet it. I've seen people describe it as the most misunderstood thing in JavaScript and after spending time on it I completely believe that. But I think I've finally got a solid grip on it so let me try to explain it the way it eventually made sense to me.
What Is this?
The simplest way I can put it is this – this is a keyword that refers to whoever is currently calling the function. It's not a fixed value. It changes depending on how and where a function is called. That's the thing that trips everyone up at first. You look at this and think it means one thing but it actually means different things in different situations.
Think of it like a pronoun. If I say "he kicked the ball" you need context to know who "he" is. Same with this. You need to look at who's calling the function to know what this refers to in that moment.
A simpler way to think about it – this points to the object that owns the current execution. If a method belongs to an object and you call it through that object, this is that object. If a regular function is called on its own with no object attached, this is something else entirely. Let's look at actual examples.
this Inside a Regular Function
When you call a plain function by itself not attached to any object, this behaves differently depending on whether you're in strict mode or not. In non-strict mode this becomes the global object. In a browser that's the window object. In strict mode it's undefined.
function showThis() {
console.log(this);
}
showThis(); // In browser: Window object (or undefined in strict mode)
Honestly for a beginner the main takeaway here is just – a standalone function not called on any object has a this that's not very useful. You won't usually need this inside plain functions like this. The important cases are objects and classes.
this Inside an Object
This is where this actually becomes useful. When a function is a method of an object and you call it through that object, this refers to that object. The object is the one calling the function so this becomes that object.
let student = {
name: "Aryan",
age: 17,
greet: function() {
console.log("Hi, my name is " + this.name + " and I am " + this.age + " years old.");
}
};
student.greet(); // Hi, my name is Aryan and I am 17 years old.
When student.greet() is called, JavaScript looks at what's on the left of the dot – that's student – and sets this to that object for the duration of that function call. So this.name becomes student.name which is "Aryan".
Let me show you why this matters with two objects:
let student1 = {
name: "Aryan",
greet: function() {
console.log("Hello, I am " + this.name);
}
};
let student2 = {
name: "Priya",
greet: function() {
console.log("Hello, I am " + this.name);
}
};
student1.greet(); // Hello, I am Aryan
student2.greet(); // Hello, I am Priya
Same function logic but different this each time because different objects are calling it. This is the core of how object methods work.
The Problem This Creates – And Why call, apply, bind Exist
Here's a situation. You have two objects. One has a method. The other doesn't. But you want the second object to use the first object's method. Do you copy paste the function? That defeats the whole point of reusable code.
This is exactly the problem that call, apply, and bind solve. They let you borrow a function from one object and run it in the context of another object. You're essentially telling JavaScript – run this function but set this to be whatever I tell you instead of figuring it out yourself.
Let's build up to it with an example.
let student1 = {
name: "Aryan",
age: 17,
introduce: function(course, city) {
console.log("I am " + this.name + ", age " + this.age + ", studying " + course + " in " + city);
}
};
let student2 = {
name: "Priya",
age: 18
};
student2 has no introduce method. But we want it to use student1's introduce. Here's how all three solutions work.
call() – Borrow a Function and Run It Immediately
call() lets you call a function and manually set what this should be. You pass the object you want as this first, then any arguments the function needs one by one after that.
student1.introduce.call(student2, "Data Science", "Mumbai");
// I am Priya, age 18, studying Data Science in Mumbai
What happened here – we took the introduce function that belongs to student1 and ran it with this set to student2. So this.name became "Priya" and this.age became 18. Then we passed "Data Science" and "Mumbai" as regular arguments.
The function ran immediately. call() doesn't save anything for later. It executes right then and there with the context you specified.
apply() – Same as call but Arguments Go in an Array
apply() does exactly the same thing as call(). The only difference is how you pass the arguments. Instead of listing them one by one you pack them into an array.
student1.introduce.apply(student2, ["Web Development", "Delhi"]);
// I am Priya, age 18, studying Web Development in Delhi
Same result as before but the arguments are passed as an array ["Web Development", "Delhi"] instead of individually.
When would you use apply instead of call? When your arguments are already stored in an array. Say you have a function that needs three values and those three values are sitting in an array you got from somewhere – apply lets you pass that array directly without having to unpack it manually.
let details = ["Computer Science", "Bangalore"];
student1.introduce.apply(student2, details);
// I am Priya, age 18, studying Computer Science in Bangalore
Clean and convenient when the data is already in array form.
bind() – Same Idea but Returns a New Function Instead of Running It
bind() is the one that's a little different from the other two. While call() and apply() both execute the function immediately, bind() doesn't run the function at all. Instead it creates and returns a brand new function with this permanently set to whatever you specified. You can then call that new function whenever you want, as many times as you want.
let priyaIntroduce = student1.introduce.bind(student2);
priyaIntroduce("Physics", "Chennai");
// I am Priya, age 18, studying Physics in Chennai
priyaIntroduce("Chemistry", "Pune");
// I am Priya, age 18, studying Chemistry in Pune
So priyaIntroduce is now a new function that will always use student2 as this no matter when or how you call it. The binding is permanent in that new function.
You can also pre-fill arguments with bind if you want:
let priyaInCS = student1.introduce.bind(student2, "Computer Science");
priyaInCS("Hyderabad");
// I am Priya, age 18, studying Computer Science in Hyderabad
priyaInCS("Kolkata");
// I am Priya, age 18, studying Computer Science in Kolkata
Here we bound both the this context and the first argument. The second argument still gets passed when calling. This technique of pre-filling arguments is called partial application and it's genuinely useful in real code.
bind() is great for situations where you need to pass a function to something else – like an event listener or a callback – and you want to make sure this is correct whenever that function eventually runs. With call and apply the function runs immediately so they don't help there. bind is the one that creates a storable, callable version.
Comparison – call vs apply vs bind
Here's the clearest way I can put all three side by side:
call – sets this and runs the function immediately, arguments passed one by one separated by commas.
apply – sets this and runs the function immediately, arguments passed as a single array.
bind – sets this but does NOT run the function, returns a new function with that context locked in, can be called later.
If you need to run it now and have individual values – use call. If you need to run it now and have an array of values – use apply. If you need to run it later or store it or pass it around – use bind.
Assignment
Step 1 – Create an Object With a Method Using this
let teacher = {
name: "Mr. Sharma",
subject: "Mathematics",
introduce: function(school, city) {
console.log("I am " + this.name + ", I teach " + this.subject + " at " + school + " in " + city);
}
};
teacher.introduce("DPS", "Delhi");
// I am Mr. Sharma, I teach Mathematics at DPS in Delhi
Step 2 – Borrow That Method Using call()
let teacher2 = {
name: "Ms. Verma",
subject: "Science"
};
teacher.introduce.call(teacher2, "Kendriya Vidyalaya", "Mumbai");
// I am Ms. Verma, I teach Science at Kendriya Vidyalaya in Mumbai
Step 3 – Use apply() With Array Arguments
let details = ["Ryan International", "Bangalore"];
teacher.introduce.apply(teacher2, details);
// I am Ms. Verma, I teach Science at Ryan International in Bangalore
Step 4 – Use bind() and Store the Function
let vermaIntroduce = teacher.introduce.bind(teacher2);
vermaIntroduce("St. Mary's", "Chennai");
// I am Ms. Verma, I teach Science at St. Mary's in Chennai
vermaIntroduce("Amity School", "Noida");
// I am Ms. Verma, I teach Science at Amity School in Noida
Stored as a separate function, called twice, this stays as teacher2 both times. The bind worked exactly as expected.
Quick Recap
this is a keyword that refers to whoever is calling the function, its value changes based on context
Inside an object method, this refers to the object the method belongs to
In a standalone function, this refers to the global object or undefined in strict mode
call() borrows a function, sets this manually, runs immediately, arguments passed individually
apply() does the same as call but arguments go in an array
bind() sets this and returns a new function without running it, useful for saving and calling later
All three exist to let you control what this is instead of letting JavaScript decide
Honestly once this concept landed for me a lot of things from the classes and objects topics started making even more sense. Like why we write this.name inside a class constructor – the constructor is being called on the new object so this is that object. It's all connected.