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

What this means in JavaScript (simple explanation)
Many people finds the concept of this very confusing but we will uncover this in very simple terms so that you can never forget.
In simple terms, this means who is calling the function, it represents the current execution context. It also depends where you are using this , if you are using it in browser then it represents windows object & in case of node environment it represents empty object.
When a function runs, this refers to the object that is executing (calling) that function.
console.log(this); // in browser -> {}
console.log(this); // in node -> window object
this inside normal functions
this behavior is different in normal functions vs arrow functions. We will understand this behavior later in objects by various examples let's see.
In case of browser when we use this in different types of functions output is always a window object, but in case of node environment it represent global object.
function show1() {
console.log(this);
}
show1(); // Window (or global object)
const show2 = function() {
console.log(this);
};
show2(); // Window (or global object)
const show3 = () => {
console.log(this);
};
show3(); // Window (or global object)
this inside objects
let person = {
name: "Rahul",
greet() {
console.log(this.name);
}
};
person.greet(); // Rahul
let person = {
name: "Rahul",
greet: () => {
console.log(this.name);
}
};
person.greet(); // undefined
Here this refers to the person object such that person.name will print "Rahul". As in this case person is calling the greet function that's why this inside greet function refers to person.
In case of normal functions, this always refers to the upper scope in which they are written means here this comes under greet & greet comes under person so now this will points to the person object. Its a simple trick to remember.
But in case of arrow functions, this always refers to the upper of the upper scope in which they are written means here this comes under greet and greet comes under person and then person comes under window object or global object but window.name doesn't exist that's why undefined prints.
const filmSet = {
crew: "Spot boys",
prepareProps() {
console.log(`Outer this.crew: ${this.crew}`);
function arrangeChairs() {
console.log(`Inner this.crew: ${this.crew}`);
}
arrangeChairs();
const arrangeLights = () => {
console.log(`Arrow this.crew: ${this.crew}`);
};
arrangeLights();
},
};
filmSet.prepareProps();
// Output --
// Outer this.crew: Spot boys
// Inner this.crew: undefined
// Arrow this.crew: Spot boys
What call() does
call() method borrows a this reference and give it to the function with some arguments but this reference always passed first followed by other arguments.
In other words, call() simply call the function but injecting a this reference to this function where this reference can be any object or something else.
let person1 = {
name: "Rahul"
};
let person2 = {
name: "Amit"
};
function greet() {
console.log("Hello " + this.name);
}
greet.call(person1); // Hello Rahul
greet.call(person2); // Hello Amit
function greetUser(age) {
console.log(`\({this} is \){age} years old`);
}
greetUser.call("kuldeep", 25); // kuldeep is 25 years old
greetfunction is called usingcall()method, which takesperson1to this functionNow
person1object reference is embedded to thisgreetfunctionSo in the
greetfunction,thisrefers to theperson1object such that "Rahul" prints
What apply() does
apply() method is same as call() method. The only difference is in there arguments passed, in the apply() method we passed other arguments except this reference in form of an array which then automatically extracts in order.
So in call() method, arguments are passed by separated values but in case of apply() method arguments are passed in form of array.
let person = { name: "Kuldeep" };
function greet(age, city) {
console.log(`\({this.name} is \){age} from ${city}`);
}
greet.apply(person, [25, "Delhi"]); // Kuldeep is 25 from Delhi
What bind() does
bind() method is same as call() method. The only difference is that it does not runs immediately means it returns the function reference in some variable and whenever we want to call the function, we can just call the variable using parenthesis.
In other words, bind() simply binds the output and hold it to a variable, and whenever we want to use it, we can just simply call it.
let person = { name: "Kuldeep" };
function greet(age, city) {
console.log(`\({this.name} is \){age} from ${city}`);
}
let greetUser = greet.bind(person, 25);
greetUser("Delhi"); // Kuldeep is 25 from Delhi
Difference between call, apply, and bind
| Feature | call() | apply() | bind() |
|---|---|---|---|
| Calls function immediately? | Yes | Yes | No |
| Arguments format | Normal | Array | Normal |
| Returns new function? | No | No | Yes |
Overall core functionality is same for all these 3 methods, differ in their uses cases simply.