# Spread vs Rest Operators in JavaScript

Both operators are written as three dots — `...` — yet they do completely opposite things depending on where you place them. This single syntactic choice led to one of the most common points of confusion in modern JavaScript. The good news: once you understand the core mental model, it clicks permanently.

<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text"><em>Spread expands a collection into individual pieces. Rest gathers individual pieces into a collection.</em></div>
</div>

Think of it like breathing: spread is exhaling — pushing values outward into a space — while rest is inhaling — pulling values inward into a container. The dots are the same; the direction of data is opposite.

![](https://cdn.hashnode.com/uploads/covers/696f9f5589255b82f81f6b17/5e479ffe-0896-4c74-8d98-69a26817205a.png align="center")

* * *

* * *

**Chapter 01**

## The Spread Operator

* * *

The spread operator takes an **iterable** — an array, string, Set, or any object with `[Symbol.iterator]` — and **expands** its contents in-place. You use it wherever a list of values is expected.

### Spreading into Arrays

```javascript
const fruits = ['apple', 'banana'];
const veggies = ['carrot', 'daikon'];

// Combine arrays — no .concat() needed
const grocery = [...fruits, ...veggies];
// ['apple', 'banana', 'carrot', 'daikon']

// Clone an array (shallow copy)
const copy = [...fruits];

// Insert in the middle
const mixed = ['lemon', ...fruits, 'fig'];
// ['lemon', 'apple', 'banana', 'fig']
```

### Spreading into Function Calls

Before spread, passing an array to a function expecting individual arguments required `.apply()`. Now it's effortless:

```javascript
const scores = [42, 91, 17, 68];

// Old way
Math.max.apply(null, scores);

// New way — clean and readable
Math.max(...scores);  // 91

// Works with any function
function greet(name, role) {
  return `Hello ${name}, the ${role}!`;
}
const args = ['Ada', 'engineer'];
greet(...args);  // 'Hello Ada, the engineer!'
```

### Spreading Objects

Object spread (ES2018) copies enumerable own properties from one object into another — the cleaner alternative to `Object.assign()`:

```javascript
const defaults = { theme: 'light', lang: 'en', grid: 12 };
const userPrefs = { theme: 'dark', lang: 'fr' };

// Merge with override — later keys win
const config = { ...defaults, ...userPrefs };
// { theme: 'dark', lang: 'fr', grid: 12 }

// Shallow clone an object
const snapshot = { ...config };

// Add / override specific properties
const updated = { ...config, grid: 16 };
// { theme: 'dark', lang: 'fr', grid: 16 }
```

> **⚠️ Shallow Only**
> 
> Spread creates a **shallow copy**. Nested objects and arrays are still shared by reference. If you need a deep clone, use `structuredClone(obj)` or a library like Lodash.

* * *

* * *

Chapter 02

## The Rest Operator

* * *

Rest does the inverse. It **collects** multiple individual values into a single array. You see it in two places: function parameter lists and destructuring assignments.

### Rest in Function Parameters

When you don't know how many arguments a function will receive, rest gathers the extras into a real array — replacing the old, awkward `arguments` object:

```javascript
// Sum any number of arguments
function sum(...nums) {
  return nums.reduce((acc, n) => acc + n, 0);
}
sum(1, 2, 3);       // 6
sum(10, 20, 30, 40); // 100

// Mix named params with rest
function logger(level, ...messages) {
  messages.forEach(msg =>
    console.log(`[${level}] ${msg}`)
  );
}
logger('INFO', 'Server started', 'Port 3000', 'PID 1042');
```

> **📌 Rest Must Be Last**
> 
> The rest parameter **must always be the final parameter** in the list. Writing `function bad(...items, last)` is a syntax error — rest collects everything remaining, so nothing can follow it.

### Rest in Array Destructuring

```javascript
const [first, second, ...remaining] = [10, 20, 30, 40, 50];

console.log(first);     // 10
console.log(second);    // 20
console.log(remaining); // [30, 40, 50]

// Useful for grabbing a queue's head
const [head, ...tail] = taskQueue;
```

### Rest in Object Destructuring

```javascript
const user = {
  id: 7,
  name: 'Alan',
  password: 's3cr3t',
  role: 'admin'
};

// Pluck what you need; collect the rest
const { password, ...safeUser } = user;

console.log(safeUser);
// { id: 7, name: 'Alan', role: 'admin' }

// safeUser is now safe to expose publicly
```

* * *

* * *

Chapter 03

## Side-by-Side Comparison

* * *

| Property | Spread ... | Rest ... |
| --- | --- | --- |
| **Direction** | Expands outward | Collects inward |
| **Used in** | Function calls, array literals, object literals | Function parameters, destructuring |
| **Input type** | Iterable or object | Multiple individual values |
| **Output type** | Individual values | An Array |
| **Position rule** | Anywhere in the list | Must be last |
| **Count** | Use multiple times | Only once per signature |

<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text"><strong>Quick Mental Check : </strong>Ask yourself: <em>Am I putting values into something?</em> → Spread. <em>Am I catching values from something?</em> → Rest. The direction of data flow is your guide.</div>
</div>

* * *

* * *

Chapter 04

## Real-World Use Cases

* * *

![](https://cdn.hashnode.com/uploads/covers/696f9f5589255b82f81f6b17/77451b47-6cc2-4aaa-bf72-9b177a8f2b89.png align="center")

## Putting It All Together

Here's a realistic example that uses *both* operators in a single function — a common pattern in component-based UI code:

```javascript
// REST: collect all extra props not explicitly named
function Button({ label, variant = 'primary', ...rest }) {
  const baseStyles = ['btn', `btn-${variant}`];

  // SPREAD: expand baseStyles into a new array
  const classes = [...baseStyles, rest.className]
    .filter(Boolean)
    .join(' ');

  // SPREAD: forward all remaining props to the element
  return `<button class="${classes}">${label}</button>`;
}

const extraProps = { disabled: true, id: 'submit' };

// SPREAD: unpack extraProps into named arguments
Button({ label: 'Save', variant: 'danger', ...extraProps });
```

* * *

* * *

Chapter 05

## Common Gotchas

### Spread on Non-Iterables

Spreading a plain object into an array literal will throw a `TypeError` because plain objects don't implement the iterable protocol. Object spread only works inside `{}`.

```javascript
const obj = { a: 1 };

[...obj]          // ❌ TypeError: obj is not iterable
({ ...obj })      // ✅ { a: 1 }   — object spread works fine

// Strings ARE iterable
[...'hello']      // ✅ ['h','e','l','l','o']
```

  
**Rest Doesn't Work Twice**

You can only have one rest element per destructuring pattern, and it must be last. Multiple rests in the same assignment is a syntax error.

```plaintext
const [...a, last] = [1,2,3];       // ❌ Rest must be last
const [...a, ...b] = [1,2,3];     // ❌ Only one rest allowed
const [x, y, ...rest] = [1,2,3]; // ✅ Correct
```

* * *

* * *

Takeaway

## The One Rule to Remember

* * *

Position determines purpose. When `...` appears where values are **consumed** (function arguments, array literals, object literals), it is **Spread**. When `...` appears where values are **defined or captured** (function parameters, destructuring patterns), it is **Rest**.

Master this distinction and you'll read and write modern JavaScript with far more confidence — and far fewer head-scratching moments at 2 AM.

<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text"><em>Same three dots. Two completely different jobs. One simple rule: are you giving or receiving?</em></div>
</div>
