JavaScript ES6: Arrow Functions When & Why You Should Use It?

ECMAScript 2015, also known as ES6, brought significant enhancements to JavaScript, including the introduction of arrow functions. Arrow functions provide a more concise syntax for writing functions, making JavaScript code more readable and maintainable.

In this tutorial, we will explore arrow functions in detail, covering their syntax, usage, and advantages over traditional function expressions. We will also discuss common use cases for arrow functions and provide examples to illustrate their usage. By the end of this tutorial, you will have a solid understanding of arrow functions and how to leverage them in your JavaScript code.

GETTING STARTED

Before JavaScript ES6, there were a handful of ways to declare a function, which can be a function declaration like this:

function add(a, b) {
    return a + b;
}
console.log(add(2, 3));

Or with function expression:

var add = function(a, b) {
    return a + b;
}
console.log(add(2, 3));

ARROW FUNCTIONS SYNTAX

For now, let’s translate both two functions above into arrow functions, which might look like this:

var add = (a, b) => {
    return a + b;
}
console.log(add(2, 3)); // 5

We eliminate the need for the function keyword and use the => syntax instead, resembling an arrow. This is why it’s commonly referred to as an “arrow function” or “fat arrow function” (though the reason for the “fat” terminology is not entirely clear).

Let’s dissect the syntax of an arrow function. Firstly, arrow functions must be written as function expressions; you cannot simply define them like regular functions. Parameters are enclosed within parentheses, similar to a traditional function. The => symbol signifies that this is an arrow function, which is then followed by the function’s body. Arrow functions are called in the same manner as regular functions. Here is the general syntax:

(param1, param2, …, paramN) => { statements } 
(param1, param2, …, paramN) => expression
// equivalent to: => { return expression; }
// Parentheses are optional when there's only one parameter name:
(singleParam) => { statements }
singleParam => { statements }
// The parameter list for a function with no parameters should be written with a pair of parentheses.
() => { statements }

Arrow functions with parameters:

var myFunction = (para1, para2) => {
    // do something
}

If your function just has a single expression, you can omit the curly brackets, the return keyword and write a whole function on a single line:

var myFunction = (para1, para2) => para1 + para2;

In this context, arrow functions enable you to perform an implicit return, which implies that the expression will be automatically returned when the function is called without explicitly using the return keyword.

var myFunction = (para1, para2) => para1 + para2;
myFunction(2, 3); // 5
var greeting = name => "Hello, my name is " + name;
greeting('Nam'); // Hello, my name is Nam

Those functions are equal to:

var myFunction = (para1, para2) => { return para1 + para2; }
myFunction(2, 3); // 5
var greeting = name => { return "Hello, my name is " + name; }
greeting('Nam'); // Hello, my name is Nam


If you enclose your function’s body in curly braces to form a block of code, even if it contains only a single statement, you must explicitly use the return keyword to return a value.

If you wish to return an object implicitly, ensure that you wrap the object in parentheses to prevent any confusion:

var test = () => { name: 'Jessica' };
test(); // undefined
// OK
var test = () => ({ name: 'Jessica' })
test(); // { name: 'Jessica' }

When the function has only one parameter, the parentheses surrounding this is optional:

// OK
var square = num => num * num;
// OK, also
var square = (num) => num * num;

If the function has two or more two parameters, the parentheses are mandatorily required, the same rule applies to a function that has no parameter:

var a = (para1, para2) => {
    // do something
}
var b = (para1, para2, para3) => {
    // do something
}
var c = () => {
    // do something
}

Some advanced syntaxes with rest and default parameters in ES6 are also supported in arrow functions:

(param1, param2, ...rest) => { statements }
var multiply = (a, b, ...c) => {
    var accumulator = a * b;
    for (var i of c) {
        accumulator *= i;
    }
    return accumulator;
};
multiply(1, 2, 3, 4, 5); // 120
(param1 = defaultValue1, param2, …, paramN = defaultValueN) => { 
statements }
var x = (para1 = 'JavaScript') => {
    return "I want to learn " + para1;
}
x(); // I want to learn JavaScript
x('HTML'); // I want to learn HTML

We will learn more about spread operator, rest, and default parameters in upcoming articles.

ARROW FUNCTIONS AND THE “THIS” KEYWORD

ypically, with regular functions, we need to carefully manage the “this” context and ensure it is bound correctly. This task can become cumbersome, especially with multiple nested functions. However, arrow functions simplify working with the “this” keyword. They do not have their own binding for “this”; instead, they inherit “this” from the surrounding code. This makes accessing “this” inside an arrow function much more straightforward.

var person = {
    name: 'Zeep',
    tasks: ['sweep the floor', 'clean the room', 'wash the dishes', 'take out the garbage'],
    doing: function() {
        this.tasks.forEach(task => {
            console.log(this.name + " needs to " + task);
        });
    }
}
person.doing();
/*
Zeep needs to sweep the floor
Zeep needs to clean the room
Zeep needs to wash the dishes
Zeep needs to take out the garbage
*/

In the code segment above, we see there is this.name inside the console. Because the arrow function does not have its own binding to this, it will go outside and find, it finds the doing() method, which belongs to the person object, then this in this case, will refer to the person object. Otherwise, with a regular function, this inside a function always refers to a global object, which is the window object. Hence, if we change the arrow function with a regular function, we get a different outcome:

var person = {
    name: 'Zeep',
    tasks: ['sweep the floor', 'clean the room', 'wash the dishes', 'take out the garbage'],
    doing: function() {
        this.tasks.forEach(function(task) {
// this now refers to the window object, and this.name is not specified, hence 'undefined' will be returned.
            console.log(this.name + " needs to " + task);
        });
    }
}
person.doing();
/* 
undefined needs to sweep the floor
undefined needs to clean the room
undefined needs to wash the dishes
undefined needs to take out the garbage
*/

While arrow functions are beneficial for use as standalone functions or non-object methods, they are not suitable for creating methods within objects.

var book = {
    title: 'Thinking, Fast and Slow',
    author: 'Daniel Kahneman',
    display: () => {
        return this.title + " is written by " + this.author;
    }
}
book.display();
// undefined is written by undefined

Arrow functions cannot be used as a constructor. They cannot be called with the new keyword.

var Book = (title, author) => {
    this.title = title;
    this.author = author;
}
var instance = new Book('To Kill a Mockingbird', 'Harper Lee'); // TypeError

When working with events, the this value inside a function should be dynamic, hence the arrow functions are not ideal in this case.

var element = document.querySelector('.elem');
element.addEventListener('click', () => {
    // this === Window
})
element.addEventListener('click', function() {
    // this === element
})

ARROW FUNCTIONS HAVE NO “ARGUMENTS”

In JavaScript, the arguments object is an array-like object accessible inside functions. It contains the values of the arguments passed to that function. Arrow functions do not have their own arguments object or bindings for this. Instead, they inherit arguments from their parent function, similar to how they inherit this.

// OK with regular function
var temp = function() {
    var arr = Array.from(arguments);
    return arr;
}
temp(1, 2, 3, 4, 5); // [1, 2, 3, 4, 5]
// Not so OK with arrow function
var temp = () => {
    var arr = Array.from(arguments);
    return arr;
}
temp(1, 2, 3, 4, 5); // Error

ARROW FUNCTIONS IN ARRAY MANIPULATION

Now that we’ve covered the basic syntax of arrow functions and explored some of their use cases, it’s important to note that arrow functions are commonly used for array manipulation with methods like map(), filter(), and reduce().

For example, we have an array of objects, and we will use the arrow function and some methods listed above to manipulate the array.

var fruits = [
    {
        name: 'pear',
        price: 20
    },
    {
        name: 'grape',
        price: 15
    },
    {
        name: 'apple',
        price: 25
    }
];

Now, let’s get the names of the fruits:

fruits.map(fruit => fruit.name); 
/*
pear
grape
apple
*/

Checking fruits have a price greater than or equal to 20:

fruits.filter(fruit => fruit.price >= 20);
// [ { name: 'pear', price: 20 }, { name: 'apple', price: 25 } ]

Summing up the price of the fruits altogether:

fruits.reduce((accumulator, fruit) => accumulator + fruit.price, 0); // 60

As we can see, using arrow functions in those case make the code looks pretty clear and concise.

Also Read:

Callback Functions in JavaScript A Beginner’s Guide (codemagnet.in)

ARROW FUNCTIONS WITH CALLBACK AND PROMISE

When dealing with asynchronous operations or promises in traditional ES5 JavaScript, the code often involves multiple functions and explicit use of the return keyword. As a result, arrow functions can be particularly useful in simplifying and enhancing the readability of asynchronous code. Here’s a straightforward example illustrating promise chaining in ES5:

aAsync()
    .then(function () { return bAsync(); })
    .then(function () { return cAsync(); })
    .done(function () { finish(); });

With ES6, this piece of code above can be translated into a more concise version:

aAsync().then(() => bAsync()).then(() => cAsync()).done(() => finish);

WHEN YOU SHOULD NOT USE ARROW FUNCTIONS

Arrow functions are incredibly useful, but they cannot completely replace regular functions. As mentioned earlier, there are specific situations where arrow functions should be avoided:

  1. Object Methods
  2. DOM Events
  3. Prototype Methods
  4. When you need to use an arguments object

Object Methods: When defining methods inside objects, arrow functions should be avoided if you intend to use the this keyword to refer to the object itself. Arrow functions do not have their own this context and will instead inherit it from the surrounding code. This can lead to unexpected behavior when trying to access object properties or methods.

Example:

const obj = {
name: 'John',
greet: () => {
console.log(`Hello, ${this.name}`); // 'this' will not refer to obj
}
};

DOM Events: When attaching event handlers to DOM elements, arrow functions should not be used if you need to access the event object or the this context inside the event handler. Arrow functions do not have their own this context and will not have access to the event object.

Example:

const button = document.getElementById('myButton');
button.addEventListener('click', () => {
console.log(this); // 'this' will not refer to the button element
});

Prototype Methods: When defining methods on a constructor’s prototype, arrow functions should be avoided. Arrow functions do not have a prototype property and cannot be used as constructors. Using arrow functions for prototype methods will result in an error when trying to instantiate objects using the constructor.

Example:

function Person(name) {
this.name = name;
}
Person.prototype.sayHello = () => {
console.log(`Hello, ${this.name}`); // 'this' will not refer to the Person instance
};

When you need to use an arguments object: Arrow functions do not have their own arguments object. If you need to access the arguments object inside a function, you should use a regular function instead of an arrow function.

Example:

function sum() {
const args = Array.from(arguments);
return args.reduce((acc, val) => acc + val, 0);
}

In these scenarios, it’s best to use regular functions to ensure the expected behavior and functionality of your code. Arrow functions should be used judiciously, keeping in mind their limitations and the specific use cases where they provide the most benefit.

In conclusion, ES6 arrow functions offer a concise and elegant way to write functions in JavaScript. Their streamlined syntax, along with lexical scoping of this, makes them a powerful addition to the language. By understanding how arrow functions work and their various use cases, developers can write cleaner and more readable code. Arrow functions have become a staple feature in modern JavaScript development, and mastering them is essential for any JavaScript developer.

Author

Sona Avatar

Written by

Leave a Reply

Trending

CodeMagnet

Your Magnetic Resource, For Coding Brilliance

Programming Languages

Web Development

Data Science and Visualization

Career Section

<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-4205364944170772"
     crossorigin="anonymous"></script>