Spread and Rest Operator
Spread operator
The spread operator, written with three consecutive dots ( ... ), is new in ES6 and gives you the ability to expand, or spread, iterable objects into multiple elements.If you can use the spread operator to spread an array into multiple elements.
const books = ["Don Quixote", "The Hobbit", "Alice in Wonderland", "Tale of Two Cities"];
console.log(...books);
Prints: Don Quixote The Hobbit Alice in Wonderland Tale of Two Cities
const primes = new Set([2, 3, 5, 7, 11, 13, 17, 19, 23, 29]);
console.log(...primes);
Prints: 2 3 5 7 11 13 17 19 23 29
const myPackage=['cheese', 'butter', 'bread', 'eggs', 'milk'];
console.log(...myPackage);
Combining arrays with concat One example of when the spread operator can be useful is when combining arrays. If you’ve ever needed to combine multiple arrays, prior to the spread operator, you were forced to use the Array’s concat() method.
const fruits = ["apples", "bananas", "pears"];
const vegetables = ["corn", "potatoes", "carrots"];
const produce = fruits.concat(vegetables);
console.log(produce);
Prints: ["apples", "bananas", "pears", "corn", "potatoes", "carrots"]
⚠️ Upcoming const Warning ⚠️ If you're following along by copy/pasting the code, then you've already declared the produce variable with the const keyword. The following code will try to re-declare and re-assign the variable, so depending on how you're running the code, it might throw an error.
Remember that variables declared with const cannot be redeclared or reassigned in the same scope.
const produce = [fruits, vegetables];
console.log(produce);
Prints: [Array[3], Array[3]]
Unfortunately, that doesn’t work.
Rest parameter The rest parameter, also written with three consecutive dots ( ... ), allows you to represent an indefinite number of elements as an array. This can be helpful in a couple of different situations. One situation is when assigning the values of an array to variables.
const order = [20.17, 18.67, 1.50, "cheese", "eggs", "milk", "bread"];
const [total, subtotal, tax, ...items] = order;
console.log(total, subtotal, tax, items);
Prints: 20.17 18.67 1.5 ["cheese", "eggs", "milk", "bread"]
printPackageContents('cheese', 'butter', 'bread', 'eggs', 'milk');
function printPackageContents(...items){
for(const item of items){
console.log(item);
}
}
You can think of the rest parameter like the opposite of the spread operator; if the spread operator is like unboxing all of the contents of a package, then the rest parameter is like taking all the contents and putting them back into the package.
Variadic functions
Another use case for the rest parameter is when you’re working with variadic functions.
Variadic functions are functions that take an indefinite number of arguments.
let’s say we have a function called sum() which calculates the sum of an indefinite amount of numbers. How might the sum() function be called during execution?
sum(1, 2);
sum(10, 36, 7, 84, 90, 110);
sum(-23, 3000, 575000);
There’s literally an endless number of ways the sum() function could be called. Regardless of the amount of numbers passed to the function, it should always return the total sum of the numbers.
Using the arguments object In previous versions of JavaScript, this type of function would be handled using the arguments object. The arguments object is an array-like object that is available as a local variable inside all functions. It contains a value for each argument being passed to the function starting at 0 for the first argument, 1 for the second argument, and so on.
function func1(a, b, c) {
console.log(arguments[0]);
// expected output: 1
console.log(arguments[1]);
// expected output: 2
console.log(arguments[2]);
// expected output: 3
}
func1(1, 2, 3);
If we look at the implementation of our sum() function, then you’ll see how the arguments object could be used to handle the variable amount of numbers being passed to it.
function sum() {
let total = 0;
for(const argument of arguments) {
total += argument;
}
return total;
}
Now this works fine, but it does have its issues:
If you look at the definition for the sum() function, it doesn’t have any parameters. This is misleading because we know the sum() function can handle an indefinite amount of arguments. It can be hard to understand. If you’ve never used the arguments object before, then you would most likely look at this code and wonder where the arguments object is even coming from. Did it appear out of thin air? It certainly looks that way.
Using the rest parameter
Fortunately, with the addition of the rest parameter, you can rewrite the sum() function to read more clearly.
function sum(...nums) {
let total = 0;
for(const num of nums) {
total += num;
}
return total;
}
This version of the sum() function is both more concise and is easier to read. Remember, we use the for...of loop to loop over any type of data that is iterable. So we'll use for...of here rather than for...in.