How to Use The Spread Operator in JavaScript

Simply put, the spread operator in JavaScript expands or unpacks the elements of an array or iterable object.

How to Use The Spread Operator in JavaScript
Photo by insung yoon / Unsplash

One of the most useful operators in the JavaScript languages is also one of the least understood.  The spread operator in JavaScript, denoted as ..., lets you expand the elements of an array or iterable object in-place and can help you to write cleaner and more succinct code in a couple of different ways.

Though conceptually the spread operator is always used to "expand" an array or iterable object, the exact usage and behavior varies a bit based on the context.  In this post, we'll look at JavaScript's spread operator, and the many different ways it can be used.

What is the Spread Operator in JavaScript?

Simply put, the spread operator in JavaScript expands or unpacks the elements of an array or iterable object.  It can be used to solve a couple of different problems:

  • extracting values from arrays and objects
  • copying arrays and objects
  • adding or removing elements
  • calling functions with arguments from an array
  • defining functions with variable arguments.

While these use cases are all conceptually similar, the exact details of how to apply the spread operator does vary a bit from use case to use case.

Note that the spread operator works with arrays and iterable objects. While most of the objects you're likely to encounter in JavaScript are iterable (including object literals such as value = {a: 1, b: 2, c: 3}), some APIs may return non-iterable objects. For the rest of this post, when we refer to objects and using the spread operator, we are referring specifically to iterable objects.

With that said, let's dig in to the various ways to use the spread operator!

JavaScript: The Definitive Guide: Master the World's Most-Used Programming Language 7th Edition

by David Flanagan

⭐️⭐️⭐️⭐️

Extracting values from an Object or Array

The spread operator is often used alongside object or array destructuring.  Destructuring is when we use a special assignment syntax which unpacks the elements of an object or array.

In this simple example, we destructure a 5 element array into 3 variables: the first value is assigned to a, the second value is assigned to b, and the remainder of the list is assigned to rest:

> array = [10, 20, 30, 40, 50]
> let [a, b, ...rest] = array
> a
10
> b
20
> rest
[ 30, 40, 50 ]

We can do something very similar with objects: we can extract specific values by key, and get the remainder of the object extracted into a different variable:

> values = {x: 10, y: 20, z: 30}
> let { x: xValue, ...rest } = values
> xValue
10
> rest
{ y: 20, z: 30 }

Note that the spread operator and the "rest" params are not actually required for destructuring–but they are very common.  If you don't actually care about the rest of the object or array, you can do destructuring without the spread operator:

> array = [10, 20, 30]
> [a] = array
> a
1

> values = {x: 10, y: 20, z: 30}
> let { x: xValue } = values
> xValue
10

If you use React, you've probably seen this pattern put to use to extract certain properties from the props object, and pass through the rest.  Consider a simple WrappedImage component which simply applies a Wrapper around an img tag:

const WrappedImage = ({ backgroundColor, ...rest }) => {
  return (
    <Wrapper color={backgroundColor}>
      <img {...rest} />
    </Wrapper>
  )
}

In this case, we extract the backgroundColor prop for the Wrapper, and pass all the rest of the properties through to the img.  We don't care to unpack all of the properties that an img tag can take–whatever is passed into our component, aside from backgroundColor will be passed through untouched.

Removing values from an Array or Object

Observant readers will note that the code above, by extracting the "rest" values with a spread operator, also has the effect of producing arrays and objects with elements removed:

> let array = [1, 2, 3]
> let [ _value, ...rest ] = array
> console.log(rest)
[2, 3]

In the example above, we extract the first parameter into a variable called _value. The underscore is used by convention to indicate that we don't really care about a value–it's just a placeholder.

Adding values to an Array or Object

Another way to use the spread operator is to add elements to an object or array.

First, let's add a value at the end of an array:

> let numbers = [1, 2, 3]
[ 1, 2, 3 ]
> newNumbers = [...numbers, 4]
[ 1, 2, 3, 4 ]

We can extend at both the start or the end of an array–or even both at the same time!

> let numbers = [1, 2, 3]
[ 1, 2, 3 ]
> newNumbers = [0, ...numbers, 4]
[ 0, 1, 2, 3, 4 ]

It's even possible to use multiple spread operators to combine arrays:

> let n1 = [ 1, 2, 3 ]
> let n2 = [ 4, 5, 6 ]
> [ ...n1, ...n2 ]
[ 1, 2, 3, 4, 5, 6 ]

The same techniques work for objects.  We can extend an object by applying the spread operator, and then providing additional keys and value:

> values = {x: 10, y: 20, z: 30}
> newValues = {...values, a: 10}
{ x: 10, y: 20, z: 30, a: 10 }

One thing to note with objects, however, is that the order matters for duplicated keys.  When keys are duplicated, those to the right take precedence:

> values = {x: 10, y: 20, z: 30}

> // The new value for x takes precedence:
> newValues = { ...values, x: 50}
{ x: 50, y: 20, z: 30 }

> // The old value for x takes precedence:
> newValues = { x: 50, ...values }
{ x: 10, y: 20, z: 30 }

Just like arrays, we can combine objects using multiple instances of the spread operator.  As above, the right-most value of a key takes precedence in the event of duplicated keys:

> v1 = {x: 10, y: 20, z: 30}
> v2 = {w: 40, y: 50}
> { ...v1, ...v2 } 
{ x: 10, y: 50, z: 30, w: 40 }

Copying an Array or Object

In the same way that extracting values with the spread operator can effectively be used to remove elements from arrays or objects, the spread operator can also be used to copy arrays or objects.  This is particularly useful when you are dealing with immutable data which should not be modified.

For example, the state management library Redux specifies:

"[reducers] are not allowed to modify the existing state. Instead, they must make immutable updates, by copying the existing state and making changes to the copied values"

Consider a function designed to increment a value within an object in an immutable fashion.  The spread operator can be used to easily copy and update the value, instead of modifying it:

🚫 Don't modify the existing state
const incrementValue = (state) => {
  state[value] += 1 
  return state
}

✅ Use the spread operator to copy the state
const incrementValue = (state) => {
  return {...state, state.value + 1}
}

Calling a function with arguments from an Array

The spread operator can also be used to pass arguments to a function from an array.  Consider a scenario in which we have the arguments we want to pass to a function stored in an array:

> function add(x, y, z) { return x + y + z }
> numbers = [1, 2, 3]
> add(...numbers)
6

Like some of the other uses of the spread operator, this is not the only way to pull off passing argument functions from an array.  We could unpack the values manually, or we could use the apply method on a function to accomplish the same thing:

> // manually unpack the values from an array
> add(numbers[0], numbers[1], numbers[2])

> // use apply() to pass in arguments from an Array
> add.apply(null, numbers)

Defining a function with variable arguments

Finally, the spread operator can be used to define a function which takes a variable number of arguments.  Let's imagine we wanted to define a function that could be called as f(1), f(1,2), f(1,2,3), and so forth.  Using the spread operator in the function definition, all of the arguments are packed into a single Array:

> function f(...args) { console.log(args) }
> f(1, 2, 3)
[ 1, 2, 3 ]

Similar to other usages of the spread operator, it can come at the end of a list of other arguments:

> function f(x, ...args) { console.log(args) }
> f(1, 2, 3)
[ 2, 3 ]

This usage of the spread operator is somewhat less common than others, but quite useful for certain APIs.  For example, JavaScript's console.log() function accepts a variable number of arguments to let us log multiple values in a single call.

It's worth noting that variable arguments can also be implemented using the special arguments object available inside of functions, so not every function that accepts a variable number arguments uses the spread operator.

Want to Learn More?

If you want a quick reference to the spread operator in JavaScript, be sure to check out our JavaScript Video Cheatsheet on the topic: