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 functionarg1, 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
andnew
. 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
- MDN – Arrow Functions
- When you should not use arrow functions
- When ‘Not’ to Use Arrow Functions
- Anonymous and Arrow Function
- 5 Best Ways to Write Concise Arrow Functions in JavaScript
Add comment