Hello Sunil
javascript-arrow-functions-feature-image

Arrow Functions in JavaScript

Arrow function is one of the features introduced in the ES6 version of JavaScript. It allows you to create functions in a cleaner way compared to regular functions.

In this tutorial, you will learn about JavaScript arrow function with the help of examples.

What is Arrow Function in JavaScript?

ES6 arrow function provide you with an alternative way to write a shorter syntax compared to the function expression.

Arrow functions, compared to regular function syntax, allow us to create clean, compact code.

Also Read: Functions In JavaScript โ€“ Simple Explanation

The following example defines a function expression that returns the sum of two numbers:

let add = function (x, y) {
	return x + y;
};
// Call function
console.log(add(10, 20)); // 30

The following example is equivalent to the above function expression but use an arrow function instead:

let add = (x, y) => x + y;

console.log(add(10, 20)); // 30;

Arrow Function Syntax

The syntax of the arrow function is:

let myFunction = (arg1, arg2, ...argN) => {
    statement(s)
}

Here,

  • myFunction is the name of the function
  • arg1, arg2, โ€ฆargN are the function arguments
  • statement(s) is the function body

If the body has single statement or expression, you can write arrow function as:

let myFunction = (arg1, arg2, ...argN) => expression

Letโ€™s take a look at some examples to learn and understand arrow functions in JavaScript.

Arrow Function with No Argument

If a function doesn’t take any argument, then you should use empty parentheses.

For example,

let greet = () => console.log('Hello');
greet(); // Hello

Also remember, in the case of single-line function, the return keyword and curly braces ({}) are optional.

Arrow Function with One Argument

If a function has only one argument, you can omit the parentheses.

For example,

let greet = x => console.log(x);
greet('Hello'); // Hello 

So, parentheses are optional for a SINGLE parameter.

Few more examples:

// Normal Function
const numbers = function(one) {}

// Arrow Function, with parentheses
const numbers = (one) => {}

// Arrow Function, without parentheses
const numbers = one => {}

Arrow Function with Multiple Argument

If a function has multiple arguments then parentheses are mandatory.

// multiple parameters
const multiplyAandB = (a, b) => a * b;
console.log (multiplyAandB (4, 5)); // 20

So, parentheses are required for MULTIPLE parameters.

Few more examples:

// Normal Function
const numbers = function(one, two) {}

// Arrow Function, with parentheses
const numbers = (one, two) => {}

Arrow Function with Default Parameters

Like regular functions, we can also pass a default parameter to the arrow function.

let add = (a, b=10) => {
    console.log (a + b);
}
add (-4, 3); // -1
add (4); // 14

In the above example, add (-4,3) gives -1 as output because it does not take the default value of b and add (4) gives 14 as output because here default value of b i.e., 10 is used since there is only one 4 arguments is passed during function call add (4).

Arrow Function as an Expression

You can also dynamically create a function and use it as an expression.

For example,

let age = 5;

let welcome = (age < 18) ?
  () => console.log('Baby') :
  () => console.log('Adult');

welcome(); // Baby

Multiline Arrow Functions

If a function body has multiple statements, you need to put them inside curly brackets {}.

For example,

let sum = (a, b) => {
    let result = a + b;
    return result;
}

let result1 = sum(5,7);
console.log(result1); // 12

Implicit vs Explicit Return

We have several ways of writing an arrow functions. This is because arrow functions can have either Implicit return or Explicit return keyword.

With normal functions, if you want to return something, you have to use the return keyword.

const sayHi = function(name) {
  return name
}
console.log(sayHi('Hi! Sunil')); //Hi! Sunil

Arrow functions also have that. When you use the return keyword, it’s called an explicit return.

However, arrow functions up their game and allow something called implicit return where the return keyword can be skipped.

Let’s look at some examples.

Example – 1 : Arrow Function with Explicit Return

// Single-line
const sayHi = (name) => { return name }
console.log(sayHi('Hi! Sunil')); //Hi! Sunil


// Multi-line
const sayHi = (name) => {
  return name
}
console.log(sayHi('Hi! Sunil')); //Hi! Sunil

Example – 2 : Arrow Function with Implicit Return

// Single-line
const sayHi = (name) => name
console.log(sayHi('Hi! Sunil')); //Hi! Sunil

// Multi-line
const sayHi = (name) => (
  name
)
console.log(sayHi('Hi! Sunil')); //Hi! Sunil

Notice the difference? When you use curly braces {}, you need to explicitly state the return. However, when you don’t use curly braces, the return is implied and you don’t need it.

There’s actually a name for this. When you use curly braces like in Example 1, it’s called a block body. And the syntax in Example 2 is called a concise body.

โญ๏ธ Here are the rules:

  • Block body โžก๏ธ return keyword is required
  • Concise body โžก๏ธ return keyword is implied and not needed

Example – 3 : Implicit Returns with Object Literals

So, Block body is where you use curly braces and have an explicit return. Concise body is where you don’t use curly braces, and you skip the return keyword.

Alright let’s see the third example:

Sometimes, you may wish to declare an object within an arrow function. These will be called object literals, which must be wrapped within parentheses.

Otherwise, the curly brackets of the object will be mistaken as a sequence of statements to a function and not a key in the object literal.

const me = () => { name: "Sunil" };
console.log(me()); // undefined ๐Ÿ˜ฑ

Why isn’t it returning our object. Don’t worry, let’s fix it by wrapping it in parentheses.

const me = () => ({ name: "Sunil" });
console.log(me()); // { name: 'Sunil' } โœ…

โญ๏ธ Here’s the rule:

  • For a concise body, wrap object literal in parentheses

this with Arrow Function

Inside a regular function, this keyword refers to the function where it is called.

However, this is not associated with arrow functions. Arrow function does not have its own this. So whenever you call this, it refers to its parent scope.

For example,

Inside a regular function

function Person() {
    this.name = 'Sunil',
    this.age = 25,
    this.sayName = function () {

        // this is accessible
        console.log(this.age);

        function innerFunc() {

            // this refers to the global object
            console.log(this.age);
            console.log(this);
        }

        innerFunc();

    }
}

let x = new Person();
x.sayName();

//Output: 
//25
//undefined
//Window {}

Here, this.age inside this.sayName() is accessible because this.sayName() is the method of an object.

Also Read: Simplifying JavaScript โ€“ this Keyword

However, innerFunc() is a normal function and this.age is not accessible because this refers to the global object (Window object in the browser). Hence, this.age inside the innerFunc() function gives undefined.

Inside an arrow function

function Person() {
    this.name = 'Jack',
    this.age = 25,
    this.sayName = function () {

        console.log(this.age);
        let innerFunc = () => {
            console.log(this.age);
        }

        innerFunc();
    }
}

const x = new Person();
x.sayName();

//Output: 
//25
//25

Here, the innerFunc() function is defined using the arrow function. And inside the arrow function, this refers to the parent’s scope. Hence, this.age gives 25.

Arguments Binding with Arrow Function

Regular functions have arguments binding. That’s why when you pass arguments to a regular function, you can access them using the arguments keyword.

For example,

let x = function () {
    console.log(arguments);
}
x(4,6,7); // Arguments [4, 6, 7]

Arrow functions do not have arguments binding. When you try to access an argument using the arrow function, it will give an error.

For example,

let x = () => {
    console.log(arguments);
}

x(4,6,7); 
// ReferenceError: Can't find variable: arguments

To solve this issue, you can use the spread syntax.

For example,

let x = (...n) => {
    console.log(n);
}

x(4,6,7); // [4, 6, 7]

Uses for JavaScript Arrow Functions

First and foremost, arrow functions make excellent callback functions. Arrow functions are also great for compact code, writing anonymous functions, simplifying event listeners, etc.

By far, however, they are used in JavaScript iterator methods. Such methods include .map() and .reduce(), to name a couple.

.map() method allows us to iterate over the items in an Array. With an arrow function we can make an efficient and clean line of code:

//declare an Array
const myArr = [1, 2, 3, 4, 5]
const multiplyValsByTwo = myArr.map(num => num * 2)

console.log(myArr); //[ 1, 2, 3, 4, 5 ]
console.log(multiplyValsByTwo); //[ 2, 4, 6, 8, 10 ]

Here, the argument being passed to map() method is an arrow function. So, map() method is passing on each number one by one into the arrow function, where the number will then be multiplied by 2 then, a new array is created after multiplying each value, leaving the original array untouched.

Arrow Function with Promises and Callbacks

Arrow functions provide better syntax to write promises and callbacks.

For example,

// ES5
asyncFunction().then(function() {
    return asyncFunction1();
}).then(function() {
    return asyncFunction2();
}).then(function() {
    finish;
});

Can be written as

// ES6
asyncFunction()
.then(() => asyncFunction1())
.then(() => asyncFunction2())
.then(() => finish);

Benefits of Using Arrow Function

  • Arrow function make the this keyword more manageable.
  • It is easier to read and write.
  • We do not need to worry about call, apply, bind and new. They have no effect on arrow functions.
  • Arrow functions provide better syntax to write promises and callbacks.

In a normal function, the this keyword may be bound to different values based upon the context in which the function was called.

Arrow functions use their lexical scope for this.

What does it mean? – Lexical this

Arrow functions do not have their own this. Thatโ€™s why they use the this value of the scope they are enclosed in. This is very useful for Object-Oriented style of programming in JavaScript.

Limitations of Arrow Function

Now that you are familiar with arrow function and how to type less, while making your code more terse, you are probably ready to remove every trace of a function keyword in any project you are working on.

Not so fast. Arrow function do not make sense everywhere. Typically you will avoid using the arrow function in the following scenario:

Limitation 1: You should not use arrow functions to create methods inside objects

Arrow functions do not have their own binding of this. As a result, you generally will not want to use them as methods in your objects.

Example:

let person = {
    name: 'Sunil',
    age: 25,
    sayName: () => {

        // this refers to the global .....
        //
        console.log(this.age);
    }
}

person.sayName(); // undefined

Limitation 2: You should not use arrow functions in event handlers

Suppose that you have the following input text field:

<input type="text" name="username" id="username" placeholder="Enter a username">

And you want to show a greeting message when users type their usernames. The following shows the <div> element that will display the greeting message:

<div id="greeting"></div>

Once users type their usernames, you capture the current value of the input and update it to the <div> element:

const greeting = document.querySelector('#greeting');
const username = document.querySelector('#username');
username.addEventListener('keyup', () => {
  greeting.textContent = 'Hello ' + this.value;
});

However, when you execute the code, you will get the following message regardless of whatever you type:

Hello undefined

It means that the this.value in the event handler always returns undefined.

As mentioned earlier, the arrow function doesnโ€™t have its own this value. It uses the this value of the enclosing lexical scope. In the above example, the this in arrow function references the global object.

In the web browser, the global object is window. The window object doesnโ€™t have the value property. Therefore, the JavaScript engine adds the value property to the window object and sets its values to undefined.

To fix this issue, you need to use a regular function instead. The this value will be bound to the <input> element that triggers the event.

username.addEventListener('keyup', function () {
    input.textContent = 'Hello ' + this.value;
});

Limitation 3: You cannot use an arrow function as a constructor

As for the arrow function:

const sayMyName = () => console.log(My name is ${name});

new sayMyName('Sunil'); 
// => Uncaught TypeError: sayMyName is not a constructor

To fix this issue, you need to use a regular function instead.

function sayMyName(){
  console.log(My name is ${name}); 
}

new sayMyName('Sunil'); // => Sunil

So it is advisable to avoid using the arrow function for event handlers, object methods, prototype methods, and functions that use the arguments object.

Conclusion

Arrow functions are fun to use. They make you write shorter, concise code. But they may also be harder to debug sometimes e.g. when using implicit return:

// not immediately obvious when scanning the code
() => ({ foo: 'bar' })

// more verbose; but much clearer outcome
function () {
  return { foo: 'bar' };
}

However, arrow functions are great when working with one-off functions, simple returns, callbacks, and iterator methods.

We hope you enjoyed this post. Please share the post or leave a comment if you enjoyed the post.

Resources

How useful was this post?

Click on a star to rate it!

Average rating 0 / 5. Vote count: 0

No votes so far! Be the first to rate this post.

We are sorry that this post was not useful for you!

Let us improve this post!

Tell us how we can improve this post?

Similar articles you may like

Sunil Pradhan

Hi there ๐Ÿ‘‹ I am a front-end developer passionate about cutting-edge, semantic, pixel-perfect design. Writing helps me to understand things better.

Add comment

Stay Updated

Want to be notified when our article is published? Enter your email address below to be the first to know.

Sunil Pradhan

Hi there ๐Ÿ‘‹ I am a front-end developer passionate about cutting-edge, semantic, pixel-perfect design. Writing helps me to understand things better.