ES6 Rest Parameters and Spread Operators

Click to share! ⬇️

ES6 Rest Parameters and Spread Operators

This section of our series on ES6 features looks at the new Rest and Spread Operators. An almost constant requirement in programming is the ability to easily take a group of values, and put them into an array. Additionally, it is also quite common to need to take values in an array, and extract each value to it’s own entity so to speak. The new Rest and Spread operators do just that for us when writing JavaScript in ES6. Let’s take a look at making use of ES6 Rest and Spread operators here.


Introducing the REST Parameter in ES6

The rest parameter is this sequence of three dots ... used in a function declaration to specify that there may be several remaining arguments, but we will gather them all up and place them into an array. In other words, the rest of the arguments will be collected with the rest parameter. Rest refers to gathering up several parameters, and putting them all into a single array. To summarize: In ES6, the final argument of a function declaration can be preceded by .... This collects all the remaining arguments when the function is called, into an array. They call it a rest parameter because it gets the rest of the parameters passed to a function.

Let’s declare a function called displayTags(), and note that we are passing postId as an argument and ...tags as an argument. The three dots that precede tags is the rest symbol. It will gather up all of the remaining parameters to the function. Inside the function, we just log out tags instanceof Array. Finally we simply call displayTags() while passing in 4 parameters as you see. We get the output of true, since tags will be set to an array.

'use strict';
let displayTags = function (postId, ...tags) {
    console.log(tags instanceof Array);
};
displayTags(25, 'php', 'javascript', 'laravel');

// true

Taking this same example, we will not log out tags which we know is an array. We see the output of [ “php”, “javascript”, “laravel” ]. It is clear to see that ...tags gathered up all of the parameters other than the first argument which was postId.

'use strict';
let displayTags = function (postId, ...tags) {
    console.log(tags);
};
displayTags(25, 'php', 'javascript', 'laravel');

// Array [ "php", "javascript", "laravel" ]

Let us now run the same code, but this time around we will only pass one value when we call the function. We will pass the postId only, but still log out the tags variable. We still get an empty array for ...tags. Even though there are no additional parameters to gather up, tags still gets set to an empty array.

'use strict';
let displayTags = function (postId, ...tags) {
    console.log(tags);
};
displayTags(25);

// Array [  ]

Length of a function using rest

In this example of the displayTags() function, we will declare it again with postId in the first argument position, and ...tags in the second argument position. Upon running the code, we find the length of the function to be 1. This means that when you access the length of a function, the rest parameter is ignored. The output of 1 is referring to postId here.

'use strict';
let displayTags = function (postId, ...tags) {
};
console.log(displayTags.length);

// 1

Length of arguments when using rest

Here we’ll make use of a similar snippet of ES6, but now we will have a look at arguments.length and see what we get. Notice we call the displayTags() function with four arguments of 25, php, javascript, and laravel. The result is 4 when we run the code. Pretty cool! Even though it looks like there are 2 parameters when the function was declared, postId and ...tags, arguments.length is going to refer to the actual function call. In this case we passed in 4 arguments, so this is why arguments.length is 4.

'use strict';
let displayTags = function (postId, ...tags) {
    console.log(arguments.length);
};
displayTags(25, 'php', 'javascript', 'laravel');

// 4

Dynamic functions using rest

This example is a little different. The first parameter of this dynamic function is a rest parameter for ...tags, and the body of the function just returns tags. If we make a call to the function passing in ‘php’, ‘javascript’, and ‘laravel’, we see the resulting array of [ “php”, “javascript”, “laravel” ]. This just means you can make use of a rest parameter inside of a dynamic function.

'use strict';
let displayTags = new Function("...tags", "return tags;");

console.log(displayTags('php', 'javascript', 'laravel'));

// Array [ "php", "javascript", "laravel" ]

Obligatory Addition Function

Let’s take a stab at the obligatory summing function which can take any number of arguments. We simply declare sum and use the rest parameter as our only parameter as ...numbers. In the body of the function, we actually make use of an arrow function which we just learned about to implement JavaScript’s native reduce. As you can see by the examples, each time we call sum and pass different collections of numbers we get the right answer.

'use strict';

function sum(...numbers) {
    return numbers.reduce((previous, current) => previous + current);
}

console.log(sum(1, 1));
console.log(sum(4, 4, 4));
console.log(sum(5, 10, 15, 100));

// 2
// 12
// 130

Let’s look at one more example of a rest parameter. Here we can see the argument list is a rest parameter placed in parentheses since it is an arrow function. We need to do this as ...args is implying multiple arguments. Since the rest parameter must be the last argument of a function, there can only be one rest parameter in a function. If the rest parameter is not last, your script will throw an error.

'use strict';
((...args) => {
    console.log(args);
})('First', 'Second', 'Third');

// Array [ "First", "Second", "Third" ]

Introducing the ES6 SPREAD Operator

The ES6 Spread operator is related to the rest parameter but works in almost the opposite way. The spread operator in ES6 is used to spread out the elements of an array into a list of arguments to the function. The spread operator can be used anywhere in the collection of arguments, not just the last as with rest. Let’s see a few examples of the spread operator in action.

Here we set up a hypothetical array of userids represented by three different numbers. Note that we make a call to the Math.max() function. Math.max() accepts as many arguments as you can throw at it, and it will return the argument with the highest value. When we call Math.max() we pass in userids while making use of the spread operator. What this does is to take the array of userids, and breaks it apart into three separate arguments as we call the function. We can see the result is 22 which is the userid with the highest value.

'use strict';
let userids = [10, 15, 22];
let newestUser = Math.max(...userids);
console.log(newestUser);

// 22

Creating a new array with spread

Here is a kind of neat use of the spread operator where we set up the same array we used already. This time however, we want to use the spread operator to take that array and copy it into a new array. So when we see […userids], we can almost interpret that as

[10, 15, 22]

. Logging out newUserIdsArray does indeed give us Array [ 10, 15, 22 ].

'use strict';

let userids = [10, 15, 22];
let newUserIdsArray = [...userids];
console.log(newUserIdsArray);

// Array [ 10, 15, 22 ]

Spreading out empty values

If we apply the spread operator to an array of empty values, this will result in those values being undefined. We can see here the spread operator being applied to [,,]. The second comma does not count since JavaScript allows you to have trailing commas in an array. This is why we get two undefined values rather than three.

'use strict';

let newUserIdsArray = [...[,,]];
console.log(newUserIdsArray);

// Array [ undefined, undefined ]

Using spread on a string

Let’s again put Math.max() to use, but this time we will pass in a string preceded by the spread operator. Whoa! Getting crazy here! It turns out, you can use the spread operator on strings as well. So when we run this example the string is divided into 9 different values as a list, and we get the maximum value of 9 as we see here.

'use strict';

let stringy = Math.max(...'123456789');
console.log(stringy);

// 9

Let’s make use of actual word characters in this example. We apply the spread operator to ‘Boo Yeah!’ and surround it with brackets. What this says is, break apart each single value in the string, then immediately place each individual value into an array. When we run the code, that is exactly what we get as you can see here.

'use strict';

let stringy = [...'Boo Yeah!'];
console.log(stringy);

// Array [ "B", "o", "o", " ", "Y", "e", "a", "h", "!" ]

Like we mentioned, the spread operator has no rules as to where you can use it like the rest parameter. The rest parameter must be last, but this is not the case for the spread operator. Check out this example where we apply the spread operator to the string argument of ‘Foo’ in the second position. When we run the code we can see ‘Boo’ stays intact, ‘Foo’ gets spread out like we would expect, and ‘Too’ is left in tact.

'use strict';

let stringy = ['Boo', ...'Foo', 'Too'];
console.log(stringy);

// Array [ "Boo", "F", "o", "o", "Too" ]

Summing with spread

Again we set up an arrow function which accepts to parameters, num1 and num2. This input, results in the output of num1 + num2 as we can see. Next up, we put together an array of numbers to add together, nums. Finally, we make a call so sum() passing in the array of nums preceded by the spread operator .... As we expect, the spread operator here extracts each value and feeds it to the sum function.

'use strict';

let sum = (num1, num2) => num1 + num2;
let nums = [1, 2];
console.log(sum(...nums));

// 3

Destructuring with the spread operator

Here we set up an array of characters. We then take that array and assign it to a new array. Notice we make use of the spread operator on the left hand side of an assignment operator in this example.

'use strict';

let reallycool = 'So Cool'.split('');
console.log(reallycool);
// Array [ "S", "o", " ", "C", "o", "o", "l" ]

let [...result] = reallycool;
console.log(result);
// Array [ "S", "o", " ", "C", "o", "o", "l" ]

[, , , ...result] = reallycool;
console.log(result);

// Array [ "C", "o", "o", "l" ]

ES6 Rest Parameters and Spread Operators Summary

In summary we have learned that when you want to declare a function and make use of any number of arguments, you make use of the rest parameter in ES6. You can use a rest parameter as the only one when declaring the function, or you can declare several parameters and include a rest parameter as long as it is the last one in the parameter list. The rest parameter always comes last. So instead of doing this sum(num1, num2, num3, num4) you do this sum(…nums) during function declaration.

The spread operator does pretty much the opposite. You place … directly before an array, and the spread operator will take that array and break it up into a list of arguments for the function to process as it is called. So instead of calling a function like so sum(2, 2), you can call it like this sum(…nums), assuming nums is an array of numbers.

Click to share! ⬇️