When not to use an Arrow Functions?

When not to use an Arrow Functions?

Hi there everyone! I hope you are doing good, I am back with another article, and this time it is an unconventional topic -- When not to use arrow functions?

Pre-requisites

  1. The reader should have a basic knowledge of what is ES6 arrow functions, a basic syntax level understanding is more than enough.
  2. Understanding the this keyword in JS is a plus. Please check my blog if not seen already The "this" keyword in JS uWu.

Let's start

If you are continuing you have a basic knowledge of ES6 arrow functions and the one thing that almost everyone loves about it is actually a very cool way to write functions, the syntax is very easy, and it looks very clean. Before starting when not to use the arrow functions let me give you a basic thumb rule if the function you are writing/converting doesn't have a this inside it, please convert it into the arrow function, go nuts!

But, If your function includes this which is very common in JS, as it is the basis of logic sharing in JS, you need to follow some gotchas, before the gotchas, let's just get the one basic right about arrow functions.

Most important basic about arrow function

Arrow function doesn't create its own context i.e this, it just uses the context, of where it was created, i.e surrounding scope.

A way to resolve the value of this inside an arrow function, is to check the value of this just before the function is being created, the value of this just before the creation of function, is the value of this inside the function.

Without further ado, let's dive deep into the gotchas --

Object Methods

Consider the following snippet of code

const me = { 
 name:"Mihir",
 talk:()=> { 
  return this;
 }
}
me.talk();

Screenshot 2022-01-23 191747.png

The output of this would be the global object, as I am running the code in the browser and not in the strict mode, this will be the window object. In the same code, if we write the talk() as normal traditional functions, we would get the me object over here. So why did this happen? The same reason I stated above Arrow function doesn't create their own context, they just use the context of the surrounding scope at the time of function creation.

Woohoo! Now we get the reason, but people will say let's debug/resolve the value of this inside the function in the way which I said above, and they will write this particular code.

const me = { 
 name:"Mihir",
 talk:this
}
me.talk;

Screenshot 2022-01-23 191938.png

Over here you will see it is the window object which tells us the story-- ok whatever was the value of this outside the function creation, is the same inside it, but people would start pulling their hair but why on earth the value of this inside the object me is the global object, i.e the window object, the person who doesn't understand this in JS, will not be able to understand the concept. There is this one rule regarding this --

Objects don't create a binding with this, functions do.

and that my friend is the reason why JS is hated by so many people. If you are coming from an OOP background, you will immediately start hating JS and say why on earth this is not equal to object me, but this is what it is.

I have taken this example in my previous blog The "this" keyword in JS, I will take that example again and we will try to resolve the value of this in that example again, with the set of rules I have given above.

const me = { 
 fName:"Mihir",
 // Tradional function only, you can write tradional function inside a obj like this also
 talk() {
  setTimeout(function () { 
   console.log(this.fName)
   },0)
 }
}
me.talk()

Screenshot 2022-01-23 192311.png

This code above will result in undefined, why? Because the callback function inside setTimeout is actually executed in a different scope and the value of this depends on how is the function executed, where is the function exected, who executes it. I will have a blog regarding this later, but for the time being, just understand it executes outside in a different scope, and therefore this is undefined.

Now you use the arrow function for the callback function inside setTimeout and boom! It starts working.

const me = { 
 fName:"Mihir",
 // Tradional function only, you can write tradional function inside a obj like this also
 talk() {
  setTimeout(()=> { 
   console.log(this.fName)
   },0)
 }
}
me.talk()

Screenshot 2022-01-23 192356.png

To check this thing we will use our golden rules, just before the callback function we will check the value of this.

const me = { 
 fName:"Mihir",
 // Tradional function only, you can write tradional function inside a obj like this also
 talk() {
  console.log(this)
  setTimeout(()=> { 
   console.log(this.fName)
   },0)
 }
}
me.talk()

Screenshot 2022-01-23 194932.png

The value of this outside the function, is the value inside the callback function.

Callback functions are generally the functions where you should be using arrow functions, but there is one catch, I will tell that later.

Do not use arrow functions with prototypes

function Person(n){ 
 this.fName=n;
}
Person.prototype.talk=function() {
 console.log(`${this.fName} started talking`)
}
Person.prototype.arrowTalk=()=> {
 console.log(`${this.fName} started talking`)
}
const me=new Person("Mihir")
me.talk() // Works
me.arrowTalk() // Doesn't work

Screenshot 2022-01-23 192732.png

Why this is not working because inarrowTalk() this of surrounding scope is taken, at the time of function creation in that scope the value of this is the window object.

Do not use the arrow functions to create Constructor Functions.

const Person=(n)=>{ 
 this.fName=n;
}

const me = new Person("Mihir") // Throws error

Screenshot 2022-01-23 193021.png

It just throws an error, no questions asked.

Do not use the arrow functions in event handlers

Wait, wait! I know people will start screaming at me because above I mentioned it is a good practice to use arrow functions inside callback functions, and event handlers are one of them. So why? This is because of how event listeners work under the hood.

document.body.addEventListener("click", function() { 
 console.log(this) // You get the body element
})

Screenshot 2022-01-23 193121.png

This is because the event listener under the hood binds the this to the element on which the event listener was registered. This is done by the event listener on its own. If you have used jQuery you might be getting some flashbacks, it's ok!

Now convert the callback function into the arrow function.

document.body.addEventListener("click", ()=> { 
 console.log(this) // window  object
})

Screenshot 2022-01-23 193208.png

Why does this happen? Because this is just an arrow function and it derives the this value from the surrounding scope when the function is declared, but all the cool devs out there won't find this as a problem, because they are cool and they would do something like this to get the element --

document.body.addEventListener("click", (e)=> { 
 console.log(e.target) 
})

Screenshot 2022-01-23 194032.png

and then it fails! why? This returns the target element, not the body element, the target element is the element from which it was triggered, body element is the element on which this particular event listener was registered. You can run the above code on any website, and click on the website at different places, you will get different elements every time.

Which is more verbose as well as declarative according to me, but those are just my thoughts.

So in which callbacks do you use the arrow function and on which one shouldn't. Basically, it depends on how the function works under the hood, to know more check out this blog "the saga of arrow functions with callback functions"

Summary

So don't use the arrow functions in --

  1. Object Methods
  2. With prototypes
  3. Creation of Constructor functions
  4. Event Handlers or such type of functions, refer blog

Till then peace! If you like my work please share! Thanks! Have a nice day!