Javascript Rest Parameter
Before we see what the rest parameter is, let’s see another interesting thing about javascript functions and that is arguments. Each javascript function except the arrow function has an implicit object named “arguments” which as the name suggests, contains the value of all the arguments passed to the function. And it means that we can pass any number of arguments to a function taking advantage of arguments. Let’s see an example; the following function returns the sum of the arguments passed to it and since it uses arguments it can calculate the sum of any number of arguments.
function addNumbers(){
let sum=0;
for(let i=0;i<arguments.length;i++){
sum+=arguments[i];
}
return sum;
}console.log(addNumbers()) //logs 0;
console.log(addNumbers(1,2)) //logs 3;
console.log(addNumbers(1,2,3,4,5)) //logs 15;
In the above code snippet, the addNumbers function iterates over the arguments object (yes, arguments is an object and not an array!) and calculates their sum. And from the 3 function calls we can see that the function can be called with 0, 2 or 5 arguments. It can be called using any number of arguments. This is similar to the params in C#.
The Rest Parameter is a functionality introduced in ES6 which also allows us to pass any number of arguments to a function just like arguments. However the arguments is an implicit object but the rest parameter needs to be defined as a function parameter. A parameter is made a rest parameter by prefixing the parameter with triple dots (…). The above addNumbers function can be defined using the rest parameter as shown below. It will still be called the same way as earlier.
function addNumbers(…numbers){
let sum=0;
console.log(typeof numbers);
for(let i=0;i<arguments.length;i++){
sum+=arguments[i];
}
return sum;
}console.log(addNumbers()) //logs 0;
console.log(addNumbers(1,2)) //logs 3;
console.log(addNumbers(1,2,3,4,5)) //logs 15;
Even though the arguments and the rest parameters serve the same purpose, the rest parameter has some added advantages over arguments.
The first advantage is that the rest parameter can be used with arrow functions as well. And the second advantage is availability of the array functions for the rest parameter. Since the arguments is an object, the array function like slice, splice, join, map etc cannot be used with the arguments even though it behaves like an array but those functions can be used with the rest parameter since it is an array. We can verify it using the following code snippet.
function addNumbers(){
console.log(Array.isArray(arguments));
}
function addNumbersRest(…numbers){
console.log(Array.isArray(numbers));
}
addNumbers(); //logs false
addNumbersRest(); //logs true
So we can make the addNumbers function concise taking the advantage of one of the array functions “reduce”.
// Regular function
function addNumbers(…numbers){
return numbers.length==0 ?0 : numbers.reduce((num,sum)=>sum+num);
}
// Arrow function
let addNumbers=(…numbers) => numbers.length==0 ? 0 : numbers.reduce((num,sum)=>sum+num);
Use with ordinary parameters
Another difference between the arguments and the rest parameter is their behaviour with ordinary parameters. When a function is defined with ordinary parameters then the arguments will contain the value of ordinary parameters along with all other arguments passed to the function. Whereas if a function is defined with ordinary parameters and rest parameter then the rest parameter will not contain the value of the ordinary parameters, it will contain the value of the rest of the arguments after the ordinary arguments and hence the name is the rest parameter. Let’s see an example.
function addNumbers(a,b){
//To use the array functions with the arguments object, we can convert it to an array
let numbers=Array.from(arguments);
console.log(numbers.join(','));
}
function addNumbersRest(a,b,…numbers){
console.log(numbers.join(','));
}
addNumbers(1,2,3,4,5); //logs 1,2,3,4,5
addNumbersRest(1,2,3,4,5); //logs 3,4,5
This behaviour can be helpful in the case when the ordinary parameter needs to be treated in a different way then other parameters. Let’s say we need to define a function that returns different power values of a number. We can use the mix of ordinary parameter and the rest parameter as shown in the below example.
function calculatePower(num,…powers){
return powers.map(pow=>Math.pow(num,pow));
}
console.log(calculatePower(2,1,2,3,4,5)); //logs [2, 4, 8, 16, 32]
Please note that the rest parameter must be the last parameter of the function.
The triple dot (…) operator becomes the spread operator when used in a different context. I’ll discuss that in some other post.