# Spread vs Rest Operators in JavaScript

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.

```js
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.

```js
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`.

![](https://cdn.hashnode.com/uploads/covers/6950d1ca85602739c40abd67/ecbaafa3-3493-4976-87bd-4f72fc7edf42.png align="center")

## 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:**

```js
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:**

```js
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:**

```js
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:**

```js
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:**

```js
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:**

```js
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:**

```js
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.

```js
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:**

```js
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:

![](https://cdn.hashnode.com/uploads/covers/6950d1ca85602739c40abd67/9f33484f-698f-4f7b-a57f-ecef821ecfaf.png align="center")

What it does:

![](https://cdn.hashnode.com/uploads/covers/6950d1ca85602739c40abd67/b8697301-68dd-43ac-92ef-66a1d967a44d.png align="center")

Quick Rule:

![](https://cdn.hashnode.com/uploads/covers/6950d1ca85602739c40abd67/9d73a332-ae1c-4518-b953-dcdf8b62fe22.png align="center")

## 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 |
