ES6 - A beginners guide - Rest and Spread Operator
Tags: javascript, codenewbie, beginners, webdev
Published: 2021-09-06 13:59:58

In this article I am going to look into the Rest parameter and Spread operator introduced with ES6. The purpose of these two new entries into the JS specification is to help with condensing the volume of code we write and improve readability. `rest` is used as a parameter in a function declaration to condense an indeterminate number of parameters into a single array, whereas `spread` is used in the opposite sense in that we can split iterables (arrays/objects/strings) into individual arguments. Let's at these seperately with some code examples shall we?
## Rest
### How is `...rest` done in ES5?
Typical in ES5 we were quite restricted in the supply of parameters to a function, for example:
```javascript
function add(a, b){
    return a + b;
}
console.log(add(1, 2)) // Returns 3 in a console.log
```
If we needed to handle an indeterminate amount of arguments we could reference the `arguments` keyword:
```javascript
function newFunc() {
    return arguments;
}
console.log(newFunc('Stefan', 'is', 'coding')) // Returns {0: "Stefan", 1: "is", 2: "coding"}
```
There is a problem with this approach, the return of the `arguments` keyword is an `array-like` object. Unfortunately this means we cannot use array methods such as `.filter`, or `.map`. Also, if we were to try and combine the `arguments` keyword and an ES6 arrow function it would not work because arrow functions do not contain their own `arguments` binding, this leads to the introduction of the `...rest` implementation.
### So... how to use `...rest` in ES6
As mentioned previously `...rest` is used when we do not know the number of parameters that we want to handle in a function declaration. This can be used nicely for math type functions (when we utilise some of the Array helpers introduced with ES5, I am going to cover them later in the series), for example:
```javascript
function add(...numbers){
    return numbers.reduce((sum, number) => sum + number, 0)
}
console.log(add(1,2,3,4)); // Returns 10 in a console.log
console.log(add(1,2,3,4,5,6,7,8,9,10)); // Returns 55 in a console.log
```
We might already have some parameters that will always be supplied that we want to reference by name if so we can still declare tham as parameters and use `...rest` to automatically use the rest of the parameters. For example here is a very simple example where we still want to have `num1` and `num2` as named parameters and we'll use that for the starting value in our `.reduce` helper, but also we can have reference to the rest of the parameters:
```javascript
function add(num1, num2, ...numbers){
    return numbers.reduce((sum, number) => sum + number, num1 + num2)
}
console.log(add(1,2,3,4)); // Returns 10 in a console.log
console.log(add(1,2,3,4,5,6,7,8,9,10)); // Returns 55 in a console.log
```
One thing to note though, `...rest` parameters __*must*__ appear at the end of the list of parameters. Attempting to place anything after the `...rest` parameter will trigger an `Uncaught SyntaxError` in your code.

## Spread
So, as I mentioned earlier `...spread` is used to split iterables (arrays/objects/strings) into a list of agruments, it can also be used to combine multiple arrays into one single array. Let's take a look:
### The ES5 way
```javascript
var arr1 = [1,2,3];
var arr2 = [4,5,6];
// Concatenate an array
var arr3 = arr1.concat(arr2);
console.log(arr3) // Returns [1, 2, 3, 4, 5, 6] in a console.log

// Copying an array
var arr4 = arr2;
console.log(arr4) // Returns [4, 5, 6] in a console.log
// Note: there is a risk when copying an array in this manner, see explanation after this code block

// Expanding an array
var arr5 = [1,2,3];
var expanded = [arr5, 4, 5];
console.log(expanded) // Returns [[1, 2, 3], 4, 5] in a console.log

// String to Array
var string = "stefan";
var split = string.split("")
console.log(split) // Returns ['s', 't', 'e', 'f', 'a', 'n'] in a console.log

// Math functions
var max = Math.max(arr1);
console.log(max) // Returns NaN in a console.log
```
In the "copying" example I noted that that way of work is susceptible to error, the reason for this is that in ES5 when you "copy" an array you are actually copying the reference to it, so if you update your "new" variable, you will actually update both copies of the array. Let me show you an example:
```javascript
var arr1 = [1,2,3];
var arr2 = arr1;
arr2.push(4);
console.log(arr1); // Returns [1, 2, 3, 4] in a console.log
console.log(arr2); // Returns [1, 2, 3, 4] in a console.log
```
## So how does ES6 `...spread` help?
Using the `...spread` operator in ES6 we can create a new list of arguments. This allows us to always treat the new var/let/const as a completely new item. Let's take a look at some of the above examples again in ES6 using `...spread`:
```javascript
let arr1 = [1,2,3];
let arr2 = [4,5,6];

// Concatenate an array
let arr3 = [...arr1, arr2];
console.log(arr3) // Returns [1, 2, 3, 4, 5, 6] in a console.log
// Note, the spread operator is ok in an example like this, but it is not recommended in potentially large application as it can cause excessive memory usage and risks of Stack Overflow errors. Using .concat is safer here

// Copying an array
let arr4 = [...arr2];
console.log(arr4) // Returns [4, 5, 6] in a console.log

// Expanding an array
let arr5 = [1,2,3];
let expanded = [...arr5, 4, 5];
console.log(expanded) // Returns [1, 2, 3, 4, 5] in a console.

// String to Array
let string = "stefan";
let split = [...string]
console.log(split) // Returns ['s', 't', 'e', 'f', 'a', 'n'] in a console.log

// Math functions
let max = Math.max(...arr1);
console.log(max) // Returns 3 in a console.log
```
Notice how the Math function now returns the value we expected?? Thats because instead of passing an array now (which ES5 would have done) we are passing `1, 2, 3` so the function actually compiles like this:
```javascript
let arr1 = [1, 2, 3];
// ...arr1 outputs 1, 2, 3
let max = Math.max(1, 2, 3);
```