JavaScript Spread Operator

In the previous lesson, we learned how to pull values out of arrays and objects into variables. Now let’s go the other way and learn the spread operator, which spreads the items of an array or the properties of an object into a new one.

πŸ“¦ What is the Spread Operator?

The spread operator is three dots ... placed in front of an array or object. It takes the items inside and lays them out individually into a new array or object. Think of it as unpacking a box and placing each item into a fresh box.

spread-operator.js
const numbers = [1, 2, 3];
const copy = [...numbers];
console.log(copy); // [1, 2, 3]

Let’s walk through what each line does:

  • const numbers = [1, 2, 3] makes our starting array.
  • [...numbers] spreads the three items out, one by one, into a fresh pair of square brackets.
  • const copy stores that fresh array, which holds the same values 1, 2, and 3.

So ...numbers unpacks the items, and the new array is a separate box that happens to hold the same things.

πŸ“‹ Copying an Array

To copy an array, spread it into a new pair of square brackets. This gives you a separate array, so changing the copy does not touch the original.

spread-operator.js
const original = ["a", "b", "c"];
const copy = [...original];
copy.push("d");
console.log(copy); // ["a", "b", "c", "d"]
console.log(original); // ["a", "b", "c"] β†’ unchanged

Let’s trace it line by line:

  • [...original] spreads the three letters into a brand new array stored in copy.
  • copy.push("d") adds "d" to the copy only.
  • The first console.log shows the copy now has four items.
  • The second console.log shows original still has three, because the copy and the original are two different arrays.

πŸ”— Combining Arrays

You can spread more than one array into the same new array to join them together. The items come out in the order you write them.

spread-operator.js
const fruits = ["apple", "banana"];
const veggies = ["carrot", "pea"];
const food = [...fruits, ...veggies];
console.log(food); // ["apple", "banana", "carrot", "pea"]

Here is what happens step by step:

  • ...fruits spreads "apple" and "banana" into the new array first.
  • ...veggies then spreads "carrot" and "pea" right after them.
  • Because fruits is written before veggies, its items land first, giving us one combined array in that order.

You can also drop extra values in between the spreads to add items while combining.

spread-operator.js
const more = [...fruits, "cherry", ...veggies];
console.log(more); // ["apple", "banana", "cherry", "carrot", "pea"]

This shows that spreads and plain values can sit side by side:

  • ...fruits spreads in "apple" and "banana".
  • "cherry" is a single value dropped in at that exact spot.
  • ...veggies spreads in "carrot" and "pea" after it.

Each part is placed in the order you write it, so "cherry" ends up in the middle.

🧱 Copying and Merging Objects

The spread operator works on objects too. It copies the properties of one object into a new one, and you can add new properties at the same time.

spread-operator.js
const user = { name: "Alex", age: 30 };
const updated = { ...user, age: 31 };
console.log(updated); // { name: "Alex", age: 31 }
console.log(user); // { name: "Alex", age: 30 } β†’ unchanged

Let’s break down the new object:

  • ...user copies every property from user, so we start with name: "Alex" and age: 30.
  • age: 31 comes after the spread, so it overrides the copied age.
  • updated ends up with the new age, while user keeps its original age: 30 untouched.

You can merge two objects the same way. When both objects have the same property, the one written later wins.

spread-operator.js
const defaults = { theme: "light", fontSize: 14 };
const settings = { fontSize: 16 };
const final = { ...defaults, ...settings };
console.log(final); // { theme: "light", fontSize: 16 }

Here is how the merge plays out:

  • ...defaults copies in theme: "light" and fontSize: 14 first.
  • ...settings copies in fontSize: 16 next.
  • Both objects have fontSize, and since settings is spread last, its 16 overwrites the 14.
  • theme only exists in defaults, so it carries through unchanged.

πŸ›‘οΈ Updating Without Mutating

The spread operator creates a shallow copy, which means you get a new array or object instead of changing the one you already have. This is handy when you want to add an item or update a property while keeping the original untouched.

spread-operator.js
// βœ… Add an item to an array without changing the original
const cart = ["shoes", "hat"];
const newCart = [...cart, "socks"];
console.log(newCart); // ["shoes", "hat", "socks"]
console.log(cart); // ["shoes", "hat"] β†’ still the same

Let’s see how the original stays safe:

  • ...cart spreads "shoes" and "hat" into a new array.
  • "socks" is added at the end of that new array.
  • newCart has all three items, while cart is never touched and still holds two.
spread-operator.js
// βœ… Update one property of an object without changing the original
const profile = { name: "Sam", role: "guest" };
const upgraded = { ...profile, role: "admin" };
console.log(upgraded); // { name: "Sam", role: "admin" }
console.log(profile); // { name: "Sam", role: "guest" } β†’ still the same

The same idea works for objects:

  • ...profile copies name: "Sam" and role: "guest" into a new object.
  • role: "admin" comes after the spread, so it overrides the copied role.
  • upgraded shows the new role, while profile keeps role: "guest".

Very common in React

React expects you to create new arrays and objects instead of editing the old ones. The spread operator is the standard way to update state immutably, so you will use it constantly when building React apps.

πŸͺž Shallow Copy, Not Deep Copy

A shallow copy copies the top level only. If a value inside is itself an array or object, the copy and the original still share that same inner value.

spread-operator.js
const team = { name: "Blue", members: ["Alex", "Sam"] };
const clone = { ...team };
clone.members.push("Jordan");
console.log(team.members); // ["Alex", "Sam", "Jordan"] β†’ also changed!

Let’s see why the original changed too:

  • { ...team } copies the top-level properties, so name is copied as a value but members is copied as a reference to the same array.
  • clone.members.push("Jordan") reaches into that shared array and adds "Jordan".
  • Because both objects point at the same members array, the new name shows up in team.members as well.

When you need a deep copy

For a fully independent copy, including nested arrays and objects, use structuredClone(value). The spread operator only protects the top level.

⚠️ Common Mistakes to Avoid

Mistake Problem Solution
Confusing spread with rest Both use ..., but rest collects values into an array Spread unpacks values out; rest gathers them in
Expecting a deep copy Nested arrays and objects are still shared Use structuredClone(...) for nested data
Wrong order when overriding { age: 31, ...user } puts the old age back Spread first, then list the property you want to override

πŸ”§ Try It Yourself!

  1. Make an array of three numbers and create a copy with [...arr], then add a number to the copy and confirm the original is unchanged.
  2. Combine two arrays into one using two spreads.
  3. Create an object with a couple of properties, then make a new object that copies it but overrides one property.
  4. Merge two objects that share a property and check which value wins based on order.

🧩 What You’ve Learned

  • βœ… The spread operator ... unpacks the items of an array or the properties of an object into a new one
  • βœ… [...arr] copies an array, and [...a, ...b] combines arrays
  • βœ… { ...obj, newProp: 1 } copies an object and can add or override properties
  • βœ… When merging objects, the property written last wins
  • βœ… Spread makes a shallow copy, so the original stays untouched but nested values are still shared

πŸš€ What’s Next?

The spread operator unpacks values out, but the same ... symbol can also gather values together. Let’s continue to Rest Parameters.

Share & Connect