How to Use the Spread Operator in JavaScript | The School of Code

Settings

Appearance

Choose a typography theme that suits your style

Back to How-to Guides
JavaScript

How to Use the Spread Operator in JavaScript

Learn how to use the spread operator (...) to expand arrays and objects in JavaScript.

JavaScriptSpread OperatorES6ArraysObjects

The spread operator (...) expands iterables into individual elements. It’s incredibly useful for copying, merging, and manipulating arrays and objects.

Array Spread

Copying Arrays

const original = [1, 2, 3];

// Create a shallow copy
const copy = [...original];
console.log(copy); // [1, 2, 3]

// Modifying copy doesn't affect original
copy.push(4);
console.log(original); // [1, 2, 3]
console.log(copy);     // [1, 2, 3, 4]

Merging Arrays

const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];

const merged = [...arr1, ...arr2];
console.log(merged); // [1, 2, 3, 4, 5, 6]

// Insert elements in between
const inserted = [...arr1, 'middle', ...arr2];
console.log(inserted); // [1, 2, 3, 'middle', 4, 5, 6]

Converting to Array

// String to array
const chars = [..."hello"];
console.log(chars); // ['h', 'e', 'l', 'l', 'o']

// Set to array
const set = new Set([1, 2, 2, 3]);
const unique = [...set];
console.log(unique); // [1, 2, 3]

// NodeList to array
const divs = [...document.querySelectorAll('div')];

Function Arguments

const numbers = [5, 2, 8, 1, 9];

// Pass array elements as arguments
const max = Math.max(...numbers);
console.log(max); // 9

// Instead of apply()
console.log(Math.max.apply(null, numbers)); // Old way

Object Spread

Copying Objects

const original = { a: 1, b: 2 };

// Shallow copy
const copy = { ...original };
console.log(copy); // { a: 1, b: 2 }

// Adding properties
const extended = { ...original, c: 3 };
console.log(extended); // { a: 1, b: 2, c: 3 }

Merging Objects

const defaults = { theme: 'light', lang: 'en' };
const userSettings = { theme: 'dark' };

// Later properties override earlier ones
const settings = { ...defaults, ...userSettings };
console.log(settings); // { theme: 'dark', lang: 'en' }

Updating Properties

const user = { name: 'Alice', age: 30, city: 'NYC' };

// Update specific property
const updated = { ...user, age: 31 };
console.log(updated); // { name: 'Alice', age: 31, city: 'NYC' }

// Original unchanged
console.log(user.age); // 30

Removing Properties

const user = { name: 'Alice', password: 'secret', age: 30 };

// Destructure to remove, spread the rest
const { password, ...safeUser } = user;
console.log(safeUser); // { name: 'Alice', age: 30 }

Rest Parameters

The opposite of spread - collect elements into an array:

// Rest in function parameters
function sum(...numbers) {
    return numbers.reduce((a, b) => a + b, 0);
}
console.log(sum(1, 2, 3, 4)); // 10

// Rest in destructuring
const [first, second, ...rest] = [1, 2, 3, 4, 5];
console.log(first); // 1
console.log(rest);  // [3, 4, 5]

Practical Examples

Clone and Modify

// Update item in array (immutably)
const todos = [
    { id: 1, text: 'Learn JS', done: false },
    { id: 2, text: 'Build app', done: false }
];

const updated = todos.map(todo =>
    todo.id === 1 ? { ...todo, done: true } : todo
);
console.log(updated[0].done); // true
console.log(todos[0].done);   // false (unchanged)

Conditional Properties

const includeEmail = true;

const user = {
    name: 'Alice',
    ...(includeEmail && { email: 'alice@example.com' })
};
console.log(user);
// { name: 'Alice', email: 'alice@example.com' }

Default Function Options

function createButton(options = {}) {
    const defaults = {
        text: 'Click me',
        color: 'blue',
        size: 'medium'
    };
    
    const config = { ...defaults, ...options };
    return config;
}

console.log(createButton({ color: 'red' }));
// { text: 'Click me', color: 'red', size: 'medium' }

React State Updates

// Updating state immutably
const [state, setState] = useState({
    users: [],
    loading: false,
    error: null
});

// Update single property
setState(prev => ({ ...prev, loading: true }));

// Add to array
setState(prev => ({
    ...prev,
    users: [...prev.users, newUser]
}));

Array Manipulation

const items = [1, 2, 3, 4, 5];

// Insert at position
const insertAt = (arr, index, item) => [
    ...arr.slice(0, index),
    item,
    ...arr.slice(index)
];
console.log(insertAt(items, 2, 'new')); // [1, 2, 'new', 3, 4, 5]

// Remove at position
const removeAt = (arr, index) => [
    ...arr.slice(0, index),
    ...arr.slice(index + 1)
];
console.log(removeAt(items, 2)); // [1, 2, 4, 5]

Important Notes

Shallow Copy Only

const nested = { a: { b: 1 } };
const copy = { ...nested };

copy.a.b = 2;
console.log(nested.a.b); // 2 (affected!)

// Deep copy needed for nested objects
const deepCopy = JSON.parse(JSON.stringify(nested));
// Or use structuredClone() in modern environments

Order Matters

// Later values override earlier ones
const result = { a: 1, a: 2 };
console.log(result); // { a: 2 }

const merged = { a: 1, ...{ a: 2 } };
console.log(merged); // { a: 2 }

Summary

  • [...array] - copy/expand arrays
  • {...object} - copy/merge objects
  • ...args (rest) - collect into array
  • Creates shallow copies only
  • Later properties override earlier ones
  • Essential for immutable updates