Navigating Rest Parameters and Arguments in JavaScript
Tags: javascript, beginners, rest, spread
Published: 2020-06-28 18:30:36

### Introduction

Rest parameters were introduced in JavaScript ES6 in 2015. When you don't know how many input arguments will be present, the rest parameter represents however many arguments have been used as an array. Rest parameters are not given their own individual separate name in the function expression, they're denoted by a ... prefix added to a parameter following the named parameters when defined in a function expression.

The arguments object was introduced in JavaScript ES5 in 2009. The arguments object holds all arguments that have been passed to the function, regardless of if they are named when defined in the function expression or not. It is not a real array, so it will need to be converted to one before it can be manipulated with array methods.


### Key Concept: The Spread Operator and Rest Parameters
![just resting](https://www.thetwocities.com/wp-content/uploads/2018/10/shutterstock_110304563.jpg)
* Add '...' before the last parameter
* All arguments following the second to last named parameter are placed in an array-*like* object
* For example, Object.assign can be used with the spread operator. Underbar has a built in extend function that gives the first object argument the properties of each following object passed in. If you're working on a project and you don't use underbar anywhere else but need an extend function, the spread operator allows this to be done quite easily with Object.assign:

```javascript
const obj1 = {1: 'a', 2: 'b'};
const obj2 = {3: 'c', 4: 'd'};
const obj3 = {5: 'a', 6: 'b'};

const spreadExtend = function (object, ...objects) {
    let obj = Object.assign(object, ...objects);
    return obj;
  }

console.log(spreadExtend(obj1, obj2, obj3));
// results in {1: a, 2: b, 3: c, 4: d, 5: a, 6: b}
```

* Pushing with the Spread Operator
We can avoid an unnecessarily nested array when pushing with the spread operator:
```javascript
const integerArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

const noRestParameterPushFunction = (...inputValues) => {
  const result = [];
    inputValues.forEach((element) => {
      result.push(element); // no spread operator
    });
  return result;
  }
console.log(noRestParameterPushFunction(integerArray));
// returns [[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]]

const restParameterPushFunction = (...inputValues) => {
  const result = [];
    inputValues.forEach((element) => {
      result.push(...element); // spread operator
    });
  return result;
  }
console.log(restParameterPushFunction(integerArray));
// returns [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
```

* Spread syntax can make writing operations much quicker, for example:

```javascript
const numbers = [90, 40, 5]
console.log(Math.min(numbers));
// returns NaN

console.log(Math.min(...numbers))
// returns 5
```


### Key Concept: Arguments Object
![arguments](https://s3.amazonaws.com/images.kateheddleston.com/galleries/39c77a5f-9973-4daf-87e7-2321811cce67/1429037426571_calvin-arguing_medium)
* All arguments passed to the function (if no parameters are specified) are contained in the arguments object
* This object is technically not a real array
* We can use ES6's Array.from(arguments) to turn it into an accessible array:
```javascript
// Array.from(arguments) yields an array of all of the arguments
const half = x => x / 2
const double = x => x * 2
const func = function(double, half) {
  console.log(arguments)
  console.log(Array.from(arguments))
}
func(double, half, 1, 2)
/* The console.log(arguments) yields:
[Arguments] {
  '0': [Function: double],
  '1': [Function: half],
  '2': 1,
  '3': 2
}
The console.log(Array.from(arguments)) yields:
[ [Function: double], [Function: half], 1, 2 ]
*/
```

* We can use an older method, ES5's Array.prototype.slice.call(arguments), to return a shallow copy of an array with the arguments, and specify if we only want some of the arguments:

```javascript
// Array.prototype.slice.call(arguments, 2) yields an array 
// of all of the arguments after the first two
const half = x => x / 2
const double = x => x * 2
const func = function(double, half, ...args) {
  return half(args[0]) + double(args[1])
}
const ES5func = function(double, half) {
  const argumentsAfterFirstTwo = Array.prototype.slice.call(arguments, 2);
  return half(argumentsAfterFirstTwo[0]) + double(argumentsAfterFirstTwo[1])
}
console.log(func(double, half, 1, 2));
console.log(ES5func(double, half, 1, 2));
```

### Conclusion

If you see `...` as a prefix of the last function parameter, this means the rest of the arguments will be gathered into an array for use by the function. If you see `...` in a function call, the spread is turning an array into a list of arguments. For functions that require a list of multiple arguments, the spread syntax can pass arrays to functions. Rest parameters are great for functions that can accept an unknown number of arguments.