Arrays

The JavaScript Spread Operator

Learn how JavaScript spread syntax expands iterables into arrays or function arguments and copies enumerable properties into object literals.

The spread syntax ... expands values in three places:

  • an iterable into a function’s arguments
  • an iterable into an array literal
  • an object’s own enumerable properties into an object literal

People call it the spread operator, but the specification defines it as syntax. See the MDN spread syntax reference for the complete rules.

Given

const a = [1, 2, 3]

build a longer array:

const b = [...a, 4, 5, 6]

Or copy an array shallowly:

const c = [...a]

Object spread copies own enumerable properties into a new object:

const newObj = { ...oldObj }

It does not copy the prototype or non-enumerable fields. Nested objects stay shared.

Strings are iterable:

const hey = 'hey'
const arrayized = [...hey] // ['h', 'e', 'y']

Spread also passes iterable values as separate arguments:

const add = (a, b) => a + b
const numbers = [1, 2]

add(...numbers) //3

Spread and rest are different

Rest syntax uses ... too, but it collects values instead of expanding them.

Rest in array destructuring:

const numbers = [1, 2, 3, 4, 5]
const [first, second, ...others] = numbers

Spread passes collected values as arguments:

const numbers = [1, 2, 3, 4, 5]
const sum = (a, b, c, d, e) => a + b + c + d + e
const result = sum(...numbers)

ES2018 added rest and spread for objects.

Rest properties:

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 }

Spread properties merge objects. Later keys overwrite earlier ones with the same name:

const items = { first, second, ...others }
items //{ first: 1, second: 2, third: 3, fourth: 4, fifth: 5 }

Spread is shallow. If you spread an object that contains nested objects, inner references are shared. Clone deeply only when you must.

Function definitions can use rest to collect arbitrary arguments:

const logAll = (...args) => {
  console.log(args)
}

Rest must be the last parameter in a function signature. Spread can appear in any argument position when calling.

Cloning before mutation is a daily pattern: const next = { ...user, name: 'Alex' } updates one field without touching the original object reference, except for shared nested objects.

You cannot spread null or undefined into an object literal. That throws. Guard optional sources first:

const next = { ...base, ...(extra ?? {}) }

Merge two plain objects and log the result:

const object1 = {
  name: 'Flavio'
}

const object2 = {
  age: 35
}

const object3 = { ...object1, ...object2 }

object3.name is 'Flavio' and object3.age is 35.

Lesson completed