Rest parameters: Getting all function arguments dynamically.
When we have a function that is passed one or two arguments, it’ s quite easy to get the arguments and do what we want with them. But a problem arises when for example, a function needs to be passed up to or more than 4 arguments.
Take the sum
function below as an example:
var sum = function (a, b, c, d) { return a + b + c + d;};sum(1, 2, 3, 4);
There is great possibility of this becoming really unwieldy pretty fast. Just imagine having more than four arguments or if you can’t be certain, may be because the arguments are determined at runtime. What we really want to accomplish is to dynamically get all of the arguments passed into the function.
To drill down to the main issue:
How do you dynamically get all of a function’s arguments?
The arguments object.
This is one way of doing what we want. Using the arguments object, JavaScript has provided a way for us to dynamically get all arguments passed into a function. The arguments object is an array-like object that has elements which corresponds to the arguments passed into a function.
Inside any function, the arguments object can be used to get an array-like list of all the arguments passed into the function. It’s a native JavaScript object so there’ s is no need for it to be defined in advance, it is available as a local variable within all non-arrow functions. The elements in the arguments are accessed by calling their index, the index starts at 0.
Let's see how we can use the arguments object in our sum
function.
let sum = function () { //result: { '0': 1, '1': 2, '2': 3, '3': 4, '4': 5 } //array-like console.log(arguments); //result: 1 console.log(arguments[0]); //result: 2 console.log(arguments[1]); //calculating the sum of the arguments let total = 0; for (var i = 0; i < arguments.length; i++) { total += arguments[i]; } console.log(total);};sum(1, 2, 3, 4, 5); //pass as many arguments as you require
Inside our sum
function, the variable arguments
is automatically present. It won’t be if sum
is an arrow function. This arguments variable contains all the arguments that we passed into our sum
function and we can get any of these individual arguments using it’s index i.e the same way we get the values of elements in an array. In the code snippet above we got the arguments at index 0 and 1.
Please note that the arguments object is not an array, even though it’s almost identical to an array. Length is the only array property it has.
There is another way.
The rest parameter
Using the rest parameters introduced in ES2016 we can also accomplish this. The rest parameter allows us to represent an unknown number of arguments as an array, therefore we can use it to dynamically get all arguments passed into a function. The rest operator is represented by three dots(…) followed by a name of our choosing.
Still using our sum function as an example, let’s use the rest parameter to see how it works. Note, we have also switched to an arrow function.
let sum = (...valuesToAdd) => { //result: [ 1, 2, 3, 4, 5 ] //real array console.log(valuesToAdd); //result: 3
console.log(valuesToAdd[2]) //calculating the sum of the arguments let total = 0; for (var i = 0; i < valuesToAdd.length; i++) { total += valuesToAdd[i]; } return total;}sum(1, 2, 3, 4, 5); //pass as many arguments as you require
The rest operator makes available as an array all the arguments passed to our sum
function. Each argument can be accessed using it’s index like a normal array. In the code snippet above we got the argument at index 2.
As previously mentioned, the arguments object is not a real array, but the rest parameter is an array, this means methods like sort, map, pop, just about all array methods can be called on it. The arguments object will have to be converted to a real array before we can call any of the array methods on it.
To demonstrate this, the code below shows the result we get when we use the array method, pop
, on both a rest parameter and an arguments object. It works fine on the rest parameter but not on the arguments object.
let arrayTest = function (...values) { values.pop(); //result: [1, 5, 6, 7, 3, 2] console.log(values);
//result: TypeError: arguments.pop is not a function
console.log(arguments.pop());}arrayTest(1, 5, 6, 7, 3, 2, 4);
Argument list order when using a rest parameter
The rest parameter must come last if you want to use it with other arguments. In a function’s argument list, the rest parameter begins to the take it’s array elements from the position of the argument it occupies in the argument list down to the last one.
Correct use of a rest parameter with other arguments:
let correct = (x, y, ...values) => { // result: 1 console.log(x); //result: 5 console.log(y);
//begins from the third argument to the last
//result: [6, 7, 3, 2, 4] console.log(values);}correct(1, 5, 6, 7, 3, 2, 4);
Incorrect use:
let inCorrect = (...values, y) => { //result: Rest parameter must be last formal parameter}inCorrect(1, 5, 6, 7, 3, 2, 4);
Incorrect use of the rest parameter with other arguments will result in an error: rest parameter must be last formal parameter. If you need to use the rest parameter as part of an argument list, it must come last.
The arguments object used to be my goto method of accomplishing the task of dynamically get all of a function’s arguments but this has changed since the introduction of the rest parameters. If you haven't been using it yet, try it, you might prefer it too.
The docs is a good place to start if you want to learn more.
Thanks for reading this. I hope you find it helpful.