In regular function "this" would reference to on which that function is called, otherwise "this" will be global ( in browser "window").
In case, of call/apply/bind, this will refer to object on which that function/method is called
Arrow Function
Arrow functions are special: they don’t have their “own” this. If we reference this from such a function, it’s taken from the outer “normal” function (aka outer lexical environment).
Consider the following example, and see how "this" behave differently for regular and arrow function
const collegeGroup = {
title: "King's Sqad",
students: ["Azeem", "Pal", "PK"],
displayList() {
this.students.forEach((student) => {
// Takes 'this' from displayList() function (outer lexical scope)
console.log(`${this.title} - ${student}`);
});
},
displayListV2() {
this.students.forEach(function (student){
//forEach runs functions with this=undefined by default, so 'this' it will be undefined
console.log(`${this.title} - ${student}`);
})
}
}
collegeGroup.displayList() // ??
collegeGroup.displayListV2() // ??
Again, arrow ⇒ does't have "this", so .bind(this) does't create any binding for arrow function and lookup of "this" will look into outer lexical environment.
Arrow function does't have "arguments" like normal function
What is special object "arguments" in Javascript ?
In JavaScript, regular functions have a special object called arguments. This object is like an array that holds all the values passed into the function when it's called, even if those values weren't defined as parameters in the function's declaration.
See below example:
function AplusB() {
const [a, b] = arguments;
return a + b;
}
console.log(AplusB(1, 2));
Arrow functions have no super
Example of "super"
So arrow functions do not have super. If accessed, it’s taken from the outer function. For instance:
class Animal {
constructor(name) {
this.name = name;
}
stop() {
console.log("Animal's stop() is exectuted")
}
}
class Rabbit extends Animal {
stop() {
setTimeout(() => super.stop(), 1000); // call parent stop after 1sec
// setTimeout(function() { super.stop() }, 1000)
console.log("Rabbit's stop() is exectuted")
}
}
// Run
const myAnimal = new Rabbit("Roocca");
myAnimal.stop() //
Now, use following in-place of arrow function:
setTimeout(function(){super.stop()},1000);
And this would give error SyntaxError: 'super' keyword unexpected here
Related to Inheritance, but worth to share here, and you can think why both print the same ?
class Animal {
name = 'animal';
constructor() {
console.log(this.name);
}
}
class Rabbit extends Animal {
name = 'rabbit';
}
new Animal(); // animal
new Rabbit(); // animal
Answer: The parent `constructor` always uses its own field value for "this", not the overridden one.
Example:
const bankAccount1 = {
name: "ABC 1",
display: function() {
console.log(this.name);
// Inner function as normal function
const innerDisplay = function() {
console.log(this.name);
// callback function as normal function (*)
setTimeout(function() { console.log(this.name); }, 0)
};
innerDisplay();
}
};
const bankAccount2 = { name: "ABC 2" };
bankAccount2.newDisplay = bankAccount1.display;
Question: 1 can we tell the output of bankAccount1.display();?
Question: 2 can we tell the output of bankAccount2.newDisplay();?
Question: 3 Change line (*) to use arrow function as setTimeout(function() { console.log(this.name); }, 0) and then tell the output of above two questions ?