Did you start using the arrow functions already? Observed any strange things or not an expected output? Do not blame javascript or the previous blog.
We need to understand the arrow functions behavior of this
in an arrow function's scope, so one can decide when to use
Also, few things that are missing in arrow function from the legacy function
Before we bind to the arrow functions let's understand this
"this" binding
In arrow functions, this is not that this we know from regular functions.๐
Oops! If that was vague, the point here is - Arrow function does not have its own this in their scope, unlike regular functions.
So whenever you call this inside an arrow function, it refers to its parent's scope this
binding
Really? ๐ฎ How? See below code
const obj = {
i: 10,
arrow: () => console.log(this.i, this),
normal: function() {
console.log(this.i, this);
}
}
obj.arrow();
//this.i is undefined, as "this" will be pointing to global "this" (parent scope)
//because obj will not have "this" in its scope
obj.normal();
//here i will be 10 because the regular function has its own "this",
//which points to the current object i.e., "obj"
And below is the output
Hence, the arrow functions are best suited for non-method functions
But then, the above behavior has the below usecase
const obj = {
i: 10,
method1: function() {
console.log("method1 normal function ");
console.log("i =",this.i,",this =",this);
function innerFunc() {
console.log("normal inner function");
console.log("i =",this.i,",this =",this);
}
innerFunc();
},
method2: function() {
console.log("method2 normal function");
console.log("i =",this.i,",this =",this);
const arrowInnerFunc = () => {
console.log("normal inner function");
console.log("i =",this.i,",this =",this);
}
arrowInnerFunc();
}
}
obj.method1();
obj.method2();
can you guess the output? ๐ง
obj.method1();
//method1 normal function
//i = 10 ,this = {i: 10, method1: ฦ, method2: ฦ}
//normal inner function
//TypeError: Cannot read property 'i' of undefined -> in strict mode
or
//i = undefined ,this = Window {0: global, window: Window, self: Window, document: document, name: "", location: Location, โฆ} -> not in strict mode
wait, what?๐คฏ No, do not think we learned wrong. Understand here that
In method1, innerFunc
is a normal function that will have its own this
binding, and since we are not binding any value tothis
- in strict mode, no longer possible to reference the window object through
this
inside a function, so TypeError - in sloppy mode, it is referring to window object
What happens in the case of arrowInnerFunc
?๐ค
Keep thinking on this
so at least you will get this answer correct ๐
obj.method2();
//method1 normal function
//i = 10 ,this = {i: 10, method1: ฦ, method2: ฦ}
//normal inner arrow function
//i = 10 ,this = {i: 10, method1: ฦ, method2: ฦ}
High? ๐
No, nothing new or wrong here
It is as simple as that arrowInnerFunc
is an arrow function that will get the this
binding from the parent scope where it has been called
It takes time to wrap our heads around this
. Give it some time!
call, apply, and bind
Assuming the reader is aware of these methods and how they dependent on "this" in the scope, the below section will show the arrow functions behavior
Let's define an object and functions
const obj = {
num: 10
};
window.num = 20; //defining num inside window object
const add = function (a) {
return this.num + a ;
};
const addUsingArrow = a => this.num + a ;
- call
const result1 = add.call(obj, 1) console.log(result1) //11 const arrowResult1 = addUsingArrow.call(obj, 1) console.log(arrowResult1) //21 why?
- apply
const arr = [1, 2, 3] const result2 = add.apply(obj, arr) console.log(result2) // 11 const arrowResult2 = addUsingArrow.apply(obj, arr) console.log(arrowResult2) // 21 why?
- bind
const result3 = add.bind(obj) console.log(result3(1)) //11 const arrowResult3 = addUsingArrow.bind(obj) console.log(arrowResult3(1)) //21 why?
For all the above whys, the reason is again
this
binding in arrow functions will be pointing to its parent'sthis
, and here it is global/window
prototype property
What if I say Arrow functions do not have a prototype property. Strange? but it's true!
const Foo = () => {};
console.log(Foo.prototype); // undefined
arguments
Not sure how often this being used and how many are aware of this.
Arrow functions do not have arguments
binding. The below code will help us to understand the arguments
keyword
const normalFunction = function () {
console.log(arguments);
}
const arrowFunction = () => console.log("inside arrow",arguments)
normalFunction(1,2,3)
arrowFunction(1,2,3) //error
//instead of arguments keyword, use spread operator
creating constructor
Arrow functions cannot be used as constructors and will throw an error
when used with new. Again a limitation ๐คจ
// this is how we write regular constructor
function Person() {
this.name = 'neoGrammer'
}
const person1 = new Person();
//constructor using arrow functions
const Person = () => {this.name = 'neoGrammer'};
const person1 = new Person(); // TypeError: Person is not a constructor
yield
Not going into detail about this, just a point to note that
Can not use yield, within its body
Closing notes
Yes, the blog pointed out the comparison of the arrow function to the legacy function and maybe sounded like disadvantages so not to use. But, the intention was to understand the intent and limitations, hence the right usage of the tools at the right place can be made
Hope, this blog clarified when to use and when to not use the arrow functions!
As always, open to hearing suggestions, improvisation...
Thanks for reading!
Resources