The three dots ...
that represent both of these concepts were introduced with ECMAScript2015. They literally "spread" an array or an object into its elements, which provides you with a great variety of options while coding. For example:
- Destructuring single or multiple elements.
- Concat multiple elements into one.
- Cherry-pick variables you need and sort out those you don't.
I have collected seven common use cases from my latest projects that make use of this flexible approach. Each is as simple as it is powerful.
1) Get rid of unwanted object properties
The idea is simple:
- Assume you have a Javascript object out of which you need all props but one.
- You also need the original object at a later point.
You could of course use the delete
operator and keep a copy of the original object. Using spread syntax, however, keeps your code more readable.
const domeOfCologne = {
buildStart: 1248,
buildHalted: 1560,
buildFinished: 1880,
buildingCity: 'Cologne',
buildingCountry: 'Germany'
}
// Remove the location
const { buildingCountry, ...domeInfo } = domeOfCologne;
console.log(buildingCountry) // output: 'Germany'
console.log(domeInfo) // output: {buildStart: 1248, /* ... */}
2) Join elements of several arrays together
A quite common use case is to join elements from distinct arrays. It is as easy as spreading the old arrays and adding them into a new one. Further below, you can also find a more complex method that considers nested arrays as well.
const americanNames = ['Dave', 'Joe', 'John'];
const germanNames = ['Hans', 'Mertens', 'Astrid'];
const englishNames = ['James', 'Peter', 'Boris'];
const allNames = [...americanNames, ...germanNames, ...englishNames];
console.log(allNames) // Logs an array including all elements from above
3) Add optional function arguments
Rest parameters in a function's declaration make it easy to define optional arguments. The following function will take in one mandatory argument. It will then apply a function based on its value, using the other arguments passed into the function.
function math(calcMeth, ...numbers) {
numbers.forEach(num => {
if (isNaN(num)) {
throw new TypeError('One or more arguments are not numeric')
}
});
switch (calcMeth) {
case 'sum':
return numbers.reduce((prev, curr) => prev + curr, 0);
case 'multi':
return numbers.reduce((prev, curr) => prev * curr, 1);
case 'power':
return numbers.reduce((prev, curr) => prev ** curr);
default:
throw new Error(`${calcMeth} is not a valid calculation method`)
}
}
console.log(math('sum', 2, 3)) // 5
console.log(math('multi', 2, 3)) // 6
console.log(math('power', 2, 3)) // 8
4) Extend an object with additional properties
This technique comes in especially handy when using standard configuration and dynamically extend it. A case in which I've used it myself was with a REST API endpoint that always delivers a standard HTTP - message. I would use the spread operator to additionally add a custom response from the database the frontend dev could then process
const standardResponse = {
status: 400,
title: 'client-error',
message: 'This item is already maintained in the database'
}
const extendedResponse = {
...standardResponse,
itemId: '123'
}
5) Copy an array or an object
If you want to keep the original state of an item, copying it is a save option. Like this, you have it available for further processing. This might also come in especially handy in reactive contexts, as the copy will be non-reactive.
Note that the new object also has no more reference to the original
const original = {
name: 'Mona Lisa',
creator: 'Leonardo Da Vinci'
}
const copy = { ...original };
console.log(copy) // {name: 'Mona Lisa', creator: 'Leonardo Da Vinci'}
console.log(copy === original) // false
6) Remove duplicated objects from an array
This is a more complex one, but it makes perfect use of the spread operator.
array.map
will pull out the valuesnew Map
will make sure that only unique objects are kept...
will iterate over the map and create the array
const pictures = [
{
name: 'Mona Lisa',
painter: 'Leonardo Da Vinci',
},
{
name: 'The Scream',
painter: 'Edvard Munch',
},
{
name: 'Starry Night',
painter: 'Vincent van Gogh'
},
{
name: 'The Scream',
painter: 'Edvard Munch',
}, {
name: 'Mona Lisa',
painter: 'Leonardo Da Vinci',
},
];
function removeDuplicates(arr) {
return [...new Map(arr.map((item) => [item.name, item])).values()];
}
console.log(removeDuplicates(pictures)); // Logs the three unique paintings
7) Flatten nested arrays
Nested arrays are nasty. And without libraries such as lodash, you often end up with unnecessarily spaghettified code. What if there was an easier way?
The following function will recursively iterate through an array. It pulls out all elements nested within and joins them in a new array.
const churchesOfMadrid = [
[
'Templo de Debod',
'Iglesia Parroquial de San Jerónimo el Real',
[
'San Antonio de los Alemanes',
'Convento de las Trinitarias Descalzas de San Ildefonso',
[
'Basílica de San Francisco el Grande',
'Basílica Pontificia de San Miguel'
],
],
]
]
function flattenArray(array) {
const newArray = [];
const length = array.length
for (let index = 0; index < length; index++) {
if (Array.isArray(array[index])) {
newArray.push(...flattenArray(array[index]))
} else {
newArray.push(array[index])
}
}
return newArray
}
const newArray = flattenArray(churchesOfMadrid);
console.log(newArray) // Returns the flattened array item