JavaScript Core/
Lesson

JavaScript's ... operator does two opposite things depending on where you use it. Spread expands a collection into individual pieces. RestWhat is rest?An architectural style for web APIs where URLs represent resources (nouns) and HTTP methods (GET, POST, PUT, DELETE) represent actions on those resources. gathers individual pieces into a collection. Same syntax, opposite directions. Once you internalize this, you will reach for ... constantly, it is one of the most versatile features in modern JavaScript.

The spread operatorWhat is spread operator?The three-dot syntax (...) that expands an array or object into its individual elements, commonly used to copy or merge collections.: expanding values

Spread takes an iterable (array, string, object) and expands it into individual elements. Think of it as unpacking a suitcase.

Spreading arrays

const numbers = [1, 2, 3];

const moreNumbers = [...numbers, 4, 5];
// [1, 2, 3, 4, 5]

const combined = [0, ...numbers, 4];
// [0, 1, 2, 3, 4]

Copying arrays without modifying the original:

const original = ['Alice', 'Bob', 'Charlie'];
const copy = [...original];

copy.push('David');
console.log(original); // ['Alice', 'Bob', 'Charlie'] - unchanged
console.log(copy);     // ['Alice', 'Bob', 'Charlie', 'David']
AI pitfall
AI tools spread large objects and arrays unnecessarily, creating copies when a reference would be fine. More importantly, spread creates shallow copies: nested objects are still shared by reference. If Copilot generates const copy = { ...bigObject } and you mutate a nested property on copy, the original changes too. For deep data, use structuredClone() instead.

Spreading objects

const user = { name: 'Alice', age: 25 };

// Copy and extend
const withEmail = { ...user, email: 'alice@example.com' };
// { name: 'Alice', age: 25, email: 'alice@example.com' }

// Override existing properties - last one wins
const olderUser = { ...user, age: 26 };
// { name: 'Alice', age: 26 }

Merging objects with overrides is the most common pattern:

const defaults = { theme: 'light', fontSize: 14, showSidebar: true };
const userPrefs = { theme: 'dark', fontSize: 16 };

const settings = { ...defaults, ...userPrefs };
// { theme: 'dark', fontSize: 16, showSidebar: true }

Shallow copyWhat is shallow copy?A copy of an object where top-level values are duplicated but nested objects still point to the same originals. vs deep copy

This is the single most misunderstood aspect of spread. Spread only copies one level deep.

Source dataSpread resultSafe to mutate copy?
Flat object { a: 1, b: 2 }Independent copyYes
Nested object { a: { x: 1 } }a is shared referenceNo, mutating copy.a.x changes original
Array of primitives [1, 2, 3]Independent copyYes
Array of objects [{ id: 1 }]Objects are sharedNo, mutating copy[0].id changes original
// Shallow copy problem
const user = { name: 'Alice', prefs: { theme: 'dark' } };
const clone = { ...user };

clone.prefs.theme = 'light';
console.log(user.prefs.theme); // 'light' - original was mutated!

// Deep copy solution
const safeClone = structuredClone(user);

Spreading in function calls

const numbers = [1, 5, 3, 9, 2];
const min = Math.min(...numbers);  // 1
const max = Math.max(...numbers);  // 9
02

The restWhat is rest?An architectural style for web APIs where URLs represent resources (nouns) and HTTP methods (GET, POST, PUT, DELETE) represent actions on those resources. operator: collecting values

While spread expands, rest collects. It gathers remaining elements into an array or object.

Rest in function parameters

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

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

The rest parameter must be last and can combine with regular parameters:

function logMessage(level, ...details) {
  console.log(`[${level}]`, ...details);
}

logMessage('ERROR', 'File not found', '/data/file.txt');
// [ERROR] File not found /data/file.txt

Rest in destructuringWhat is destructuring?A shorthand for pulling specific values out of an object or array into their own variables instead of accessing them one by one.

Extract specific properties while keeping everything else:

const user = {
  id: 42,
  name: 'Alice',
  email: 'alice@example.com',
  role: 'admin',
  password: 'secret'
};

const { password, ...safeUser } = user;
// safeUser = { id: 42, name: 'Alice', email: '...', role: 'admin' }
// password is extracted and discarded

This pattern is common for stripping sensitive fields before sending data to clients.

Rest with arrays

const colors = ['red', 'green', 'blue', 'yellow', 'purple'];
const [primary, secondary, ...others] = colors;

console.log(primary);   // 'red'
console.log(secondary); // 'green'
console.log(others);    // ['blue', 'yellow', 'purple']
03

Spread vs restWhat is rest?An architectural style for web APIs where URLs represent resources (nouns) and HTTP methods (GET, POST, PUT, DELETE) represent actions on those resources. at a glance

ContextOperatorDirectionExample
Function callSpreadExpand array into argumentsmyFunc(...arr)
Array literalSpreadExpand into elements[...arr, 4]
Object literalSpreadExpand into properties{ ...obj }
Function paramRestCollect argumentsfunction(...args)
DestructuringRestCollect remainingconst [a, ...rest] = arr

Memory aid: Spread = "take these apart" (outward). Rest = "gather the rest" (inward).

04

Common patterns

Immutable updates (React-style)

const todos = [
  { id: 1, text: 'Learn spread', done: false },
  { id: 2, text: 'Learn rest', done: false }
];

// Add a new todo without mutating
const withNew = [...todos, { id: 3, text: 'Practice', done: false }];

// Toggle a todo without mutating
const toggled = todos.map(t =>
  t.id === 1 ? { ...t, done: !t.done } : t
);

Removing duplicates

const numbers = [1, 2, 3, 3, 4, 4, 5];
const unique = [...new Set(numbers)];
// [1, 2, 3, 4, 5]

Flexible function arguments

function createUser(name, age, ...tags) {
  return { name, age, tags, createdAt: new Date() };
}

createUser('Alice', 25);
// { name: 'Alice', age: 25, tags: [], createdAt: ... }

createUser('Bob', 30, 'developer', 'javascript');
// { name: 'Bob', age: 30, tags: ['developer', 'javascript'], ... }
05

Quick reference

PatternSyntaxResult
Copy array[...arr]Shallow copy
Merge arrays[...a, ...b]Combined array
Copy object{ ...obj }Shallow copy
Merge objects{ ...a, ...b }b overrides a
Collect argsfunction(...args)args is a real array
Destructure restconst { a, ...rest } = objrest has everything except a
Deep copystructuredClone(obj)True deep copy (not spread)