In this article we are going to see what they are and how to use JavaScript Arrow Functions, a new feature introduced with the ES6 standard (ECMAScript 6).
What are Arrow Functions
Arrow Functions are a new syntax for defining anonymous functions in JavaScript in a more concise way. Being an abbreviated syntax, it will save us a lot of time, as well as simplifying the function scope. It is one of the most widely used features of ES6.
Currently, most browsers already support Arrow Functions, so we can use them safely. However, they are not supported by any version of Internet Explorer.
To define an Arrow Function we use the symbol "=>", whose shape reminds us of a double arrow. It is not necessary to write neither the word function nor the function opening and closing braces, being a case similar to the Lambdas of languages like Python or C#. Arrow functions can be defined in a single line.
Arrow Functions Syntax
We can define arrow functions in many ways. In this section we are going to see the most used ones, as well as the differences between an ES6 Arrow Function and a normal function.
Let's define a very simple example function that adds two numbers.
// ES5 var sumaEs5 = function(x, y) { return x + y; }; // ES6 const sumaEs6 = (x, y) => { return x + y }; console.log(sumaEs6(2, 4)); // 6
As we can see, with the arrow function we save the word function, and we can also write the function in a single line maintaining the recommended good practices.
Syntax with one parameter
In the case of using a single parameter, we can omit the parentheses surrounding the parameter. As an example, a function that calculates the square of a number:
// ES5 var cuadradoEs5 = function(x) { return x * x; }; // ES6 const cuadradoEs6 = (x) => { return x * x }; console.log(cuadradoEs6(3)); // 9
Syntax without parameters
In the case of not using any parameter, we will have to write the parentheses anyway. As an example, a function that makes an alert:
// ES5 var holaEs5 = function() { alert('Hola'); }; // ES6 const holaEs6 = () => { alert('Hola'); }; holaEs6();
Literal expression syntax
Arrow functions can also return an object in its literal expression form. Objects are defined between braces, something that would conflict with the definition of arrow functions. That is why to return a literal we will have to surround the function with parentheses. That is to say, in addition to the braces, we will have to place an opening and a closing parenthesis. As an example, this function that transforms two parameters into an object:
// ES5 var agregarIdEs5 = function(id, nombre) { return { id: id, nombre: nombre } }; // ES6 const agregarIdEs6 = (id, nombre) => ({ id: id, nombre: nombre }); console.log(agregarIdEs6(1, "Edu")); // Object {id: 1, nombre: "Edu"}
Now you know how Arrow Functions are defined, so we will see how to use them. We will also see some practical examples.
How to use Arrow Functions
We are going to see a series of examples in which you will be able to clearly see the advantages of the Arrow Functions.
Array Manipulation
A very extended use case of the Arrow Functions is the manipulation of arrays. In this example we are going to define an array of cars with their name and price. Then, we will create a function to extract the prices of all the cars with both ES5 and ES6:
const fruits = [ { name:'Apple', price:1 }, { name:'Banana', price:2 }, { name:'Peach', price:3 } ]; // ES5 var prices = fruits.map(function(fruit) { return fruits.price; }); console.log(prices); // [1, 2, 3] // ES6 const prices = fruits.map(fruit => fruit.price); console.log(prices); // [1, 2, 3]
As we have seen, the second function is shorter and more concise, being also easier to read.
Let's look at another example where we filter the numbers in an array that are divisible by three.
const array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]; // ES5 var divisiblebyFour ES5 = array.filter(function (n){ return n % 4 === 0; }); // ES6 const divisiblebyFour ES6 = array.filter(n => n % 4 === 0); console.log(divisiblebyFour ES6); // [4, 8, 12, 16, 20]
Again, the ES6 version is shorter and more concise. Let's look at another typical use case in the next section.
Promises & Callbacks
When we use callbacks in asynchronous functions, we can find a lot of functions and values that are returned or passed to other functions. If we use Promises, these expressions will be concatenated to each other as you can see in the following example where we call three asynchronous functions, one after the other. The code becomes simpler if we use Arrow Functions
// ES5 aAsync().then(function() { retbAsync(); }).then(function() { retcAsync(); }).done(function() { finish(); }); // ES6 aAsync().then(() => bAsync()).then(() => cAsync()).done(() => finish);
In addition to benefiting from a shorter syntax, we eradicate the confusion of using the word this. One of the problems with calling functions this way in ES5 is that we will have to pass the context somehow to the next function.
As we said before, when we use Arrow Functions the context is kept between functions, so let's see the differences with an example:
// ES5 API.prototype.get = function(param) { var self = this; return new Promise(function(resolve, reject) { http.get(self.uri + param, function(data) { resolve(data); }); }); }; // ES6 API.prototype.get = function(param) { return new Promise((resolve, reject) => { http.get(this.uri + param, function(data) { resolve(data); }); }); };
In ES5 we have to use several techniques to obtain the context the this, like this famous clause:
var self = this;.
By means of this clause or closure, we obtain the context of the parent function in ES5. On the other hand, with the ES6 Arrow function, the context of the parent function is maintained. Another method also widely used in ES5 is to use the .bind method, which in practice proves to be quite slow.
Considerations about Arrow Functions
Arrow Functions, like everything else, have their advantages and disadvantages. In this section we will see what they are.
To begin with, the syntax of the functions can be more confusing for some people and even make it more difficult to read, as it is less natural. At least, this is what some people think, but the truth is that there are more developers in favor of its use than against it.
So that you don't hate Arrow Functions because of multiple errors that you might mistakenly think are bugs, there are several things to keep in mind:
This: The word this works in a different way in Arrow Functions. The value of this cannot be modified inside the function and, even if you try, you will find that its value is the same as the one with which the function was called. The call, apply and bind methods will not alter its value either.
Constructors: Arrow functions cannot be used as constructors in the same way as other functions. If you use the reserved word new with an Arrow function, you will get an error. These functions do not have a prototype property or other internal methods. Constructors are usually used to clear objects of a class, so it is best to use the classes that have also been incorporated in ES6.
Generators: Arrow functions cannot be used as generators, which are functions defined with function* syntax.
Arguments: Arrow Functions do not have an internal variable defined as arguments as other functions do. The arguments variable is an array that allows us to obtain the arguments of a function, something useful in case a function has an indeterminate number of arguments. Remember that this functionality is not available in the Arrow Functions.
There are a few more, but these have been the top four considerations you should keep in mind.
When to use an arrow function
When and where to use Arrow functions is up to you, but here are three recommendations.
Use the classic functions - function - in the global scope and for properties defined as Object.prototype.
For the rest of the functions, except when you define a constructor, which you should use class, you can use arrow functions as long as their particular characteristics do not prevent you from creating them. In fact, it is to be expected that, as with let and const, this method will be the standard method for defining a function.