Skip to main content

Command Palette

Search for a command to run...

Spread vs Rest Operators in JavaScript

Let's go through spread and rest operators

Published
โ€ข5 min read
Spread vs Rest Operators in JavaScript
S

Frontend Developer ๐Ÿ’ป | Fueled by curiosity and Tea โ˜• | Always learning and exploring new technologies.

Here's something that confuses almost every JavaScript beginner: there are two operators that look exactly the same both are just three dots ... but they do completely opposite things.

One expands things out. The other collects things in.

By the end of this, you'll look at ... and immediately know which one it is and what it's doing. Let's go.

The Three Dots ...

Before we split them apart, let's establish what they share.

Both the spread operator and the rest operator are written as ... three dots, nothing more. JavaScript figures out which one you mean based entirely on where you use it.

Think of it like the word "run." The same word means completely different things in "I run every morning" and "a run of bad luck." Context does all the work. Same idea here.

Spread

Expanding Things Out. The spread operator takes something that's grouped together like an array or object and expands its contents out individually.

Imagine you have a box of apples. Spread tips the box over and lays every apple out on the table individually. The box is gone. Just apples.

const fruits = ["apple", "mango", "banana"];

console.log(fruits);    // ["apple", "mango", "banana"]  โ† the box
console.log(...fruits); // apple mango banana             โ† apples on table

That's it. ...fruits says don't give me the array, give me everything inside it.

Rest

Collecting Things In. The rest operator does the exact opposite. It takes a bunch of individual values and collects them into an array.

If spread tips the box over, rest is the box itself gathering loose items and packaging them together.

function collect(...items) {
  console.log(items); // ["apple", "mango", "banana"]
}

collect("apple", "mango", "banana");

You passed three separate strings. Rest collected them into one neat array called items.

Spread with Arrays

This is where spread gets genuinely useful. Here are the four things you'll do with it all the time.

Copying an array:

const original = [1, 2, 3];
const copy = [...original];

copy.push(4);

console.log(original); // [1, 2, 3] โ€” untouched
console.log(copy);     // [1, 2, 3, 4]

Without spread, doing const copy = original just creates another pointer to the same array. Change one, change both. Spread makes a real independent copy.

Merging arrays:

const frontend = ["HTML", "CSS", "JavaScript"];
const backend  = ["Node.js", "Express", "MongoDB"];

const fullStack = [...frontend, ...backend];
// ["HTML", "CSS", "JavaScript", "Node.js", "Express", "MongoDB"]

Clean and readable. No loops. No .concat().

Adding items while spreading:

const skills = ["CSS", "JavaScript"];
const updatedSkills = ["HTML", ...skills, "React"];
// ["HTML", "CSS", "JavaScript", "React"]

You can place ... anywhere in the array literal. Items before, after, or both.

Passing array items as function arguments:

const nums = [4, 8, 2, 6];

console.log(Math.max(nums));    // NaN โ€” Math.max wants numbers, not an array
console.log(Math.max(...nums)); // 8   โ€” spread unpacks them perfectly

Math.max expects individual numbers like Math.max(4, 8, 2, 6). Spread converts your array into exactly that.

Spread with Objects

Spread works on objects too โ€” and it's used constantly in modern JavaScript, especially in React.

Copying an object:

const user = { name: "Satpal", age: 25 };
const copy = { ...user };

copy.age = 30;

console.log(user.age); // 25 โ€” original untouched
console.log(copy.age); // 30

Merging objects:

const defaults = { theme: "light", language: "en", fontSize: 14 };
const userPrefs = { theme: "dark", fontSize: 18 };

const settings = { ...defaults, ...userPrefs };
// { theme: "dark", language: "en", fontSize: 18 }

When keys clash, the last one wins. userPrefs.theme overwrote defaults.theme. This pattern โ€” merge defaults, then override with user values is everywhere in real code.

Updating one field without mutating:

const user = { name: "Riya", age: 24, city: "Mumbai" };

const updated = { ...user, age: 25 };
// { name: "Riya", age: 25, city: "Mumbai" }

You spread all existing properties, then write the one you want to change. The original user object is never touched. This is the standard pattern in React state updates.

Rest

Collecting Function Arguments. Rest shines in functions. It lets you accept any number of arguments without knowing in advance how many there will be.

function sum(...numbers) {
  return numbers.reduce((total, n) => total + n, 0);
}

sum(1, 2);           // 3
sum(1, 2, 3, 4, 5);  // 15
sum(10, 20);         // 30

...numbers scoops up every argument passed in and packages them into an array. Then you can use all your normal array methods on them.

Mix regular parameters with rest:

function introduce(greeting, ...names) {
  names.forEach(name => {
    console.log(greeting + ", " + name + "!");
  });
}

introduce("Hello", "Priya", "Arjun", "Dev");
// Hello, Priya!
// Hello, Arjun!
// Hello, Dev!

greeting catches the first argument normally. ...names catches everything after it. The rest parameter must always come last nothing can follow it.

Difference:

What it does:

Quick Rule:

The Quick Reference

Spread Rest
Symbol ... ...
Direction Expands out Collects in
Used in Array literals, object literals, function calls Function parameter lists
Input Array / object / iterable Individual arguments
Output Individual values An array
Must be last? No Yes, always last parameter
Works with objects? Yes No, only in destructuring

JavaScript

Part 7 of 24

Master JavaScript from the ground up with a structured, easy-to-follow learning path designed for serious developers. This series starts with core fundamentals like variables, data types, and control flow, then gradually moves into deeper topics such as functions, scope, prototypes, asynchronous programming, and how the JavaScript engine works internally. Each lesson focuses on clarity and real understanding. You will learn not only how to write JavaScript, but why it behaves the way it does. Concepts are explained using simple examples, practical use cases, and clean coding patterns that reflect real-world development.

Up next

Destructuring in JavaScript

101 JavaScript concepts