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

Introduction:
In JavaScript, the this keyword refers to the current execution context, or the object that "owns" the running code or function. Its value is not determined by where the function is defined, but by how it is called.
Here's how this behaves in different scenarios:
Alone (Global Context): When used outside of any function or object,
thisrefers to the global object. In a web browser, this is thewindowobject, while in Node.js, it's theglobalobject.In an Object Method: When a function is called as a method of an object,
thisrefers to the object itself, allowing access to its properties and methods.For example:
const person = { name: "Alice", greet: function() { console.log(`Hello, my name is ${this.name}`); } }; person.greet();
Output:
Hello, my name is Alice
=== Code Execution Successful ===
In a Regular Function: Inside a standalone function (not as a method),
thistypically refers to the global object in non-strict mode. In strict mode,thisisundefined.In a Constructor Function: When a function is used as a constructor with the
newkeyword,thisrefers to the newly created object instance being constructed.For example:
function Car(make) { this.make = make; // 'this' refers to the new Car instance } const myCar = new Car("Toyota");In an Event Handler: In HTML event handlers,
thisusually refers to the DOM element that triggered the event.
In Arrow Functions: Arrow functions do not have their own this binding. Instead, they inherit this from the enclosing lexical scope (the scope where they were defined). This makes their behavior more predictable for callbacks.
The value of this can also be explicitly controlled using the [call()](https://developer.mozilla.org), [apply()](https://developer.mozilla.org), and [bind()](https://developer.mozilla.org) methods
this inside normal functions:
Here's an example of normal functions calling directly:
function show() {
console.log(this);
}
show();
Output:
<ref *1> Object [global] {
global: [Circular *1],
clearImmediate: [Function: clearImmediate],
setImmediate: [Function: setImmediate] {
[Symbol(nodejs.util.promisify.custom)]: [Getter]
},
clearInterval: [Function: clearInterval],
clearTimeout: [Function: clearTimeout],
setInterval: [Function: setInterval],
setTimeout: [Function: setTimeout] {
[Symbol(nodejs.util.promisify.custom)]: [Getter]
},
queueMicrotask: [Function: queueMicrotask],
structuredClone: [Function: structuredClone],
atob: [Function: atob],
btoa: [Function: btoa],
performance: [Getter/Setter],
fetch: [Function: fetch],
navigator: [Getter],
crypto: [Getter],
alert: [Function: log],
prompt: [Function (anonymous)]
}
=== Code Execution Successful ===
this inside objects:
For example:
const ranveer = {
name: "Ranveer",
profession: "Actor",
introduce() {
return `My name is \({this.name} and I am an \){this.profession}`;
}
};
console.log(ranveer.introduce());
Output:
My name is Ranveer and I am an Actor
=== Code Execution Successful ===
What call() does:
The call() method in JavaScript invokes a function immediately, allowing you to explicitly define the this context (the owner object) and pass arguments individually. It is primarily used for function borrowing, enabling one object to use a method belonging to another, thus increasing code reusability.
Key Aspects of call():
Context Setting: You can specify which object
thisrefers to within the function.Argument Passing: Arguments are passed individually, separated by commas (e.g.,
func.call(context, arg1, arg2)).
Immediate Execution: The function runs immediately when call() is invoked.
For example:
const person = {
fullName: function(city, country) {
return this.firstName + " " + this.lastName + "," + city + "," + country;
}
};
const person1 = { firstName: "John", lastName: "Doe" };
console.log(person.fullName.call(person1, "Oslo", "Norway"));
Output:
John Doe,Oslo,Norway
=== Code Execution Successful ===
Comparison to Other Methods:
apply(): Similar to
call(), but accepts arguments as an array instead of individually.bind(): Returns a new function with a bound
thiscontext, rather than executing it immediately.Note: In Python,
__call__is a special method that allows an instance of a class to be called as a function.
What apply() does:
In JavaScript, apply() calls a function with a specified this value and arguments provided as a single array (or array-like object). It is used to borrow methods from other objects or invoke functions where arguments are dynamically generated or already in an array format.
Key Aspects of apply():
Syntax:
func.apply(thisArg, [argsArray]).thisContext: The first argument (thisArg) defines thethisvalue inside the function.Arguments: The second argument is an array or array-like object, which
apply()spreads into individual arguments for the function.Difference from
call(): Whilecall()takes arguments separately (func.call(this, arg1, arg2)),apply()takes them as a single array (func.apply(this, [arg1, arg2])).Use Cases:
- Method Borrowing: Using a method from one object on a different object.
Handling Arrays: Passing arrays to functions that expect individual arguments, such as Math.max.apply(null, [1, 2, 3]).
For example:
const person = {
fullName: function(city, country) {
return this.firstName + " " + this.lastName + "," + city + "," + country;
}
};
const person1 = {
firstName: "John",
lastName: "Doe"
};
console.log(person.fullName.apply(person1, ["Oslo", "Norway"]));
Output:
John Doe,Oslo,Norway
=== Code Execution Successful ===
Note: In other contexts like R, apply() is used for row- or column-wise operations on data frames.
What bind() does:
The bind() method is used to bind a specific object to a function so that the this keyword inside that function always refers to that object. Unlike call() or apply(), the bind() method does not execute the function immediately. Instead, it returns a new function that can be executed later with the desired this context.
In JavaScript, the value of this depends on how a function is called. Sometimes when a function is passed as a callback, used inside events, or stored in another variable, the value of this can change unexpectedly. The bind() method solves this problem by permanently attaching a specific object as the this value for that function.
Another powerful feature of bind() is that it can pre-set arguments for a function. This means you can partially apply arguments in advance, and when the new function is called later, those preset arguments will automatically be included.
Because of this behavior, bind() is often used in situations such as:
When passing methods as callbacks
When working with event handlers
When ensuring a function keeps the correct object context
When performing partial function application
For example:
const person = {
fullName: function(city, country) {
return this.firstName + " " + this.lastName + "," + city + "," + country;
}
};
const person1 = {
firstName: "John",
lastName: "Doe"
};
const result = person.fullName.bind(person1, "Oslo", "Norway");
console.log(result());
Output:
John Doe,Oslo,Norway
=== Code Execution Successful ===
Difference between call, apply, and bind:
| Feature | call() |
apply() |
bind() |
|---|---|---|---|
| Purpose | Call a function with a specific this |
Call a function with a specific this |
Create a new function with fixed this |
| Executes immediately | Yes, it executes immediately | Yes, it executes immediately | No, it does executes immediately |
| Arguments | Passed individually | Passed as an array | Passed individually |
| Return value | Returns result of function | Returns result of function | Returns a new function |
Conclusion: The Magic of this, call(), apply(), and bind()
JavaScript is a little funny sometimes. The keyword this is like a confused person who keeps asking, “Who am I talking about right now?” The answer depends on who called the function. If an object calls the function, then this points to that object.
Now sometimes JavaScript forgets who it should be talking about. That’s when call(), apply(), and bind() come in like helpful friends who say, “Relax, we’ll tell you exactly who this should be!”
call()says: “Hey function, run right now and use THIS object!”apply()says the same thing but adds: “Here are your arguments in a nice little array.”bind()is a bit lazy. It says: “I won’t run the function now. I’ll just prepare a new function and remember whothisshould be.”
So in simple silly terms:
call() - run now
apply() - run now (but with array arguments)
bind() - run later
In the end, the magic of this is just about knowing which object the function is talking about, and call(), apply(), and bind() help us control that conversation.
Once you understand this magic, JavaScript stops acting weird and starts making a lot more sense.




