When and why you should use ES6 arrow functions/tradional function — and when you shouldn’t

In this article, you'll learn about JavaScript arrow functions and regular functions, what the major difference between them is, and when we should use one over the other. You'll see lots of examples that illustrate how they work.

Table of contents

  1. Syntax difference
  2. Syntaxically anonymous
  3. When you should use arrow function
  4. When you should not use arrow function

1. Syntax Diffrence

Functions are like recipes where you store useful instructions to accomplish something you need to happen in your program, like performing an action or returning a value. By calling your function, you execute the steps included in your recipe. You can do so every time you call that function without needing to rewrite the recipe again and again.

It is very important to understand how arrow function works differently compared to regular ES5 functions.

a) Regular function

Here we can see the way of deceleration and calling a regular function in JavaScript.

// function declaration
function Subtract(a,b){
   return a-b;
}
// call the function
let sum = Subtract(9,3);

b) Arrow function

Now, here is the same function expressed as an arrow function.

// By Arrow function
let Subtract = (a,b) => a-b

// call function
let ans = subtract(9,3)

It’s much shorter! We are able to omit the curly braces and the return statement due to implicit returns (but only if there is no block — more on this below).

Variations

One thing you will find fascinating when you notice the variety of syntax availible in arrow functions.

1. No parameters

If there are no parameters, you can place an empty parentheses.

() => 42

2. Single parameter

With these function, parentheses are optional

x => 42 || (x) => 42

3.Multiple parameters

Parentheses are required for these functions

(x,y) => x = y

4.Statements

With arrow functions, it is important to remember that statements need to have curly braces. Once the curly braces are present, you always need to write return as well.

Here is an example of arrow function used with if statement:

var feedTheCat = (cat) => {
  if (cat === 'hungry') {
    return 'Feed the cat';
  } else {
    return 'Do not feed the cat';
  }
}

5. Block body

If your function is in a block , you must use the explicit return statement

var addValues = (x, y) => {
  return x + y
}

6. Object literals

If you are returning an object literal, it need to be wrpped in parentheses. This also makes the interpreter clear to evaluate what is inside the parentheses.

x =>({ y: x })

Syntactically anonymous

It is important to note that arrow functions are anonymous, which means that they are not named. This will create some issues listed below.

a) Harder to debug

When you get an error, you will not be able to trace the name of the function or the exact line number where it occurred.

b) No self-Referencing

If your function needs to have a self-reference at any point (e.g. recursion, an event handler that needs to unbind), it will not work.

When you shlould use Arrow functions.

1. Lexical this

The keyword this is often considered a tricky topic in javascript. This article will help you to understand how this works.

Arrow function have lexical this , meaning the value of this will be from the parent scope in which the arrow function is present.

Now, we will se the demonstartion of how traditional function and arrow function handels this .

const printNumbers = {
  phrase: 'The current value is:',
  numbers: [1, 2, 3, 4],

  loop() {
    this.numbers.forEach(function (number) {
      console.log(this.phrase, number)
    })
  },
}

In the following code snippet printNumber object , there are two properties: phrase and numbers. There is also a method on the object, loop, which should print the phrase string and the current value in numbers

Now, You yes! you might expect the loop function to print the string and current number in the loop on each iteraton. However, in the result of running the function the phrase is actually undefined. Shocked?


This will give the following:

Output undefined 1 undefined 2 undefined 3 undefined 4```

As this shows, this.phrase is undefined, indicating that this within the anonymous function passed into the forEach method does not refer to the printNumbers object. This is because a traditional function will not determine its this value from the scope of the environment, which is the printNumbers object.

To solve this problem , you would have had to use the bind method, which explicitly sets this

Use bind ti fix the function

const printNumbers = {
  phrase: 'The current value is:',
  numbers: [1, 2, 3, 4],

  loop() {
    // Bind the `this` from printNumbers to the inner forEach function
    this.numbers.forEach(
      function (number) {
        console.log(this.phrase, number)
      }.bind(this),
    )
  },
}

printNumbers.loop()

This will give the expected output

Output
The current value is: 1
The current value is: 2
The current value is: 3
The current value is: 4

Arrow function provides a more easier and direct way of dealing with this. Since their this value is determined based on the lexical scope, the inner function called in forEach can now access the properties of the outer printNumbers object, as demonstrated:

const printNumbers = {
  phrase: 'The current value is:',
  numbers: [1, 2, 3, 4],

  loop() {
    this.numbers.forEach((number) => {
      console.log(this.phrase, number)
    })
  },
}

printNumbers.loop()

This will give the expected result:

Output
The current value is: 1
The current value is: 2
The current value is: 3
The current value is: 4

These examples establish that using arrow functions in built-in array methods like forEach, map, filter, and reduce can be more intuitive and easier to read, making this strategy more likely to fulfill expectations.

When you shlould not use Arrow functions.

1. Object Methods

While arrow functions are excellent as parameter functions passed into array methods, they are not effective as object methods because of the way they use lexical scoping for this. Using the same example as before, take the loop method and turn it into an arrow function to discover how it will execute:

const printNumbers = {
  phrase: 'The current value is:',
  numbers: [1, 2, 3, 4],

  loop: () => {
    this.numbers.forEach((number) => {
      console.log(this.phrase, number)
    })
  },
}

In this case of an object method, this should refer to properties and methods of the printNumbers object. However, since an object does not create a new lexical scope, an arrow function will look beyond the object for the value of this and beyond this arrow function will lokk fro this in outer space.

2. Prototype methods

Prototype is a property ,which is what javascript uses as a blueprint for cloning.

To illustrate this,create a function and log the automatically assigned prototype property:

function myFunction() {
  this.value = 5
}

// Log the prototype property of myFunction
console.log(myFunction.prototype)

This will print the output to the console:

Output
{constructor: ƒ}

This show that in the prototype property there is an object with a constructor this also allows to use new keyword to create an instance of function.

In contrast, arrow functions do not have a prototype property. Create a new arrow function and try to log its prototype:

```const myArrowFunction = () => {}

// Attempt to log the prototype property of myArrowFunction console.log(myArrowFunction.prototype)```

This will give the following :

Output
undefined

As a result of the missing prototype property, the new keyword is not available and you cannot construct an instance from the arrow function.

3. Arguments object

Arrow functions don’t have the arguments object. Therefore, if you have a function that uses arguments object, you cannot use the arrow function.

For example, the following concat() function won’t work:

const concat = (separator) => {
    let args = Array.prototype.slice.call(arguments, 1);
    return args.join(separator);
}

Instead, you use a regular function like this:

function concat(separator) {
    let args = Array.prototype.slice.call(arguments, 1);
    return args.join(separator);
}

Summary

  • An arrow function doesn’t have its own this value. Instead, it uses the this value of the enclosing lexical scope. An arrow function also doesn’t have the arguments object.

  • Avoid using the arrow function for event handlers, object methods, prototype methods, and functions that use the arguments object.