# Spread vs Rest Operators in JavaScript

## Introduction

JavaScript's Spread & Rest Operator look identical. Both are three dots (`...`). But they do opposite things depending on where you put them.

One expands values out. The other collects values in. Once that clicks, the rest is just syntax.

* * *

## What the Spread Operator Does

The spread operator takes something iterable, like an array or object, and unpacks its contents into individual elements.

Think of it like opening a box and laying everything out on the table.

```javascript
const fruits = ['apple', 'banana', 'mango'];
console.log(...fruits); // apple banana mango
```

That's useful, but the real power shows up when you're building new arrays or objects.

```javascript
const first = [1, 2, 3];
const second = [4, 5, 6];
const combined = [...first, ...second];
// [1, 2, 3, 4, 5, 6]
```

No `concat`. No loops. You just spread both arrays into a new one.

* * *

## What the Rest Operator Does

Rest does the reverse. Instead of expanding values, it collects multiple values into a single array.

It's most useful in function parameters when you don't know how many arguments are coming in.

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

sum(1, 2, 3);        // 6
sum(10, 20, 30, 40); // 100
```

Here, `...numbers` gathers every argument into an array. You're not unpacking anything. You're bundling things up.

* * *

## The Core Difference

|  | Spread | Rest |
| --- | --- | --- |
| What it does | Expands an iterable into individual values | Collects individual values into an array |
| Where it's used | Array/object literals, function calls | Function parameter lists |
| Direction | Out (unpacking) | In (bundling) |

A quick way to remember: if the `...` is on the right side of an assignment or inside a function call, it's spread. If it's in the function definition's parameter list, it's rest.

* * *

## Using Spread with Arrays

### Copying an array

```javascript
const original = [1, 2, 3];
const copy = [...original];
copy.push(4);

console.log(original); // [1, 2, 3]
console.log(copy);     // [1, 2, 3, 4]
```

This gives you a shallow copy. Mutating `copy` won't touch `original`. That said, if the array contains objects, those objects are still shared by reference.

### Inserting values while merging

```javascript
const start = [1, 2];
const end = [5, 6];
const full = [...start, 3, 4, ...end];
// [1, 2, 3, 4, 5, 6]
```

You can drop values in between spreads. That's something `concat` can't do as cleanly.

### Passing array items as function arguments

```javascript
const nums = [3, 1, 4, 1, 5];
const max = Math.max(...nums); // 5
```

`Math.max` expects individual arguments, not an array. Spread bridges that gap without needing `.apply()`.

* * *

## Using Spread with Objects

Spread works on objects too. It copies key-value pairs into a new object.

```javascript
const defaults = { theme: 'light', lang: 'en' };
const userPrefs = { lang: 'fr', fontSize: 14 };

const settings = { ...defaults, ...userPrefs };
// { theme: 'light', lang: 'fr', fontSize: 14 }
```

When keys overlap, the last one wins. Here, `lang` from `userPrefs` overwrites the one from `defaults`.

This pattern shows up constantly in config merging, Redux reducers, and anywhere you're building objects from multiple sources.

* * *

## Practical Use Cases

### Removing a property from an object

```javascript
const user = { id: 1, name: 'Sara', password: 'secret' };
const { password, ...safeUser } = user;

console.log(safeUser); // { id: 1, name: 'Sara' }
```

Here rest is used in destructuring. You pull out the property you don't want, and everything else goes into `safeUser`.

### Handling variable function arguments

```javascript
function log(level, ...messages) {
    messages.forEach(msg => console.log(`[${level}]`, msg));
}

log('INFO', 'Server started', 'Listening on port 3000');
// [INFO] Server started
// [INFO] Listening on port 3000
```

The first argument is captured separately. Everything after goes into the rest array.

### Adding or overriding properties without mutation

```javascript
const state = { count: 0, loading: false };

const nextState = { ...state, count: state.count + 1 };
// { count: 1, loading: false }
```

You get a new object. The original is untouched. This is the standard way to handle state updates in React without mutating directly.

### Cloning and extending arrays

```javascript
const base = ['read', 'write'];
const extended = [...base, 'execute'];
// ['read', 'write', 'execute']
```

Useful when building permission sets or option lists that inherit from a base.

* * *

## A Note on Shallow Copies

Both spread and rest create shallow copies. For arrays and objects of primitives, that's fine. But if your data is nested, you'll need something deeper, like `structuredClone`, for full isolation.

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

copy.a.b = 99;
console.log(nested.a.b); // 99 (shared reference)
```

This trips people up. When you need a fully independent copy, use `structuredClone`. It recursively clones the entire structure, so nothing is shared.

```javascript
const nested = { a: { b: 1 } };
const clone = structuredClone(nested);

clone.a.b = 99;
console.log(nested.a.b); // 1 (untouched)
```

`structuredClone` is built into modern browsers and Node.js 17+, so no library needed. For deeply nested data, it's the cleaner option over spread.

* * *

## Conclusion

The same three dots, two different jobs. Spread unpacks. Rest collects. Once you see that pattern, you'll start noticing it everywhere, and using it without thinking twice.
