Work with objects and arrays using Rest and Spread
By Flavio Copes
Learn how to use the rest and spread syntax in JavaScript to expand arrays, clone objects and pass an array as function arguments using the three-dot operator.
Rest and spread are two uses of the same ... syntax. Spread expands an array, object or string into its individual pieces. Rest collects multiple values into a single array or object.
Spread
Let’s start with an array example. Given
const a = [1, 2, 3]
you can create a new array using the spread operator:
const b = [...a, 4, 5, 6]
You can also create a copy of an array using
const c = [...a]
This works for objects as well. Clone an object with:
const newObj = { ...oldObj }
Be careful: this is a shallow copy. Top-level properties are copied, but nested objects are still shared:
const person = { name: 'Ada', address: { city: 'London' } }
const clone = { ...person }
clone.address.city = 'Paris'
person.address.city // 'Paris' 😱
If you need to change nested data, clone deeper (for example with structuredClone()).
Using strings, the spread operator creates an array with each char in the string:
const hey = 'hey'
const arrayized = [...hey] // ['h', 'e', 'y']
The most useful application is passing an array as function arguments:
const numbers = [7, 3, 9]
Math.max(...numbers) // 9
(in the past you could do this using Math.max.apply(null, numbers) but that’s not as nice and readable)
Rest
Rest goes the other way. Instead of expanding values, it gathers them.
In array destructuring, the rest element collects what’s left over:
const numbers = [1, 2, 3, 4, 5]
const [first, second, ...others] = numbers
first // 1
second // 2
others // [3, 4, 5]
The rest element must be the last one. Writing [...others, last] is a syntax error.
In function parameters, rest lets you accept any number of arguments as an array:
const sum = (...nums) => nums.reduce((total, n) => total + n, 0)
sum(1, 2, 3) // 6
sum(10, 20) // 30
This replaced the old array-like arguments object, which was harder to work with.
Rest and spread for objects
ES2018 introduced rest properties, which are the same but for objects.
Rest properties collect the remaining properties into a new object:
const { first, second, ...others } = {
first: 1,
second: 2,
third: 3,
fourth: 4,
fifth: 5
}
first // 1
second // 2
others // { third: 3, fourth: 4, fifth: 5 }
This is handy when you want to remove a property from an object without mutating it. Destructure it out, and keep the rest.
Spread properties allow us to create a new object by combining the properties of the object passed after the spread operator:
const items = { first, second, ...others }
items // { first: 1, second: 2, third: 3, fourth: 4, fifth: 5 }
Order matters here. Properties spread later overwrite earlier ones with the same name, which makes this a nice way to apply defaults:
const defaults = { theme: 'light', fontSize: 16 }
const settings = { ...defaults, theme: 'dark' }
settings // { theme: 'dark', fontSize: 16 }Related posts about js: