Suggest an editImprove this articleRefine the answer for “Spread and REST operators in JavaScript: differences and examples”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**Spread (`...`)** expands an iterable into individual elements; rest (`...`) collects remaining elements into an array. Same syntax, opposite jobs. ```javascript // Spread: unpack const merged = [...[1, 2], 3]; // [1, 2, 3] // Rest: collect function sum(first, ...rest) { return first + rest.reduce((a, b) => a + b, 0); } sum(1, 2, 3); // 6 ``` **Key:** position determines role. Right side or in a call = spread. Left side in params or destructuring = rest.Shown above the full answer for quick recall.Answer (EN)Image**Spread (`...`) and rest (`...`)** share the same syntax but do opposite things. Spread unpacks an iterable into separate elements; rest collects separate elements into one array. ## Theory ### TL;DR - Spread is like dumping a bag of ingredients onto the counter: everything comes out separately - Rest is like scooping leftovers back into the bag: everything goes in together - Main difference: spread lives on the right side (or inside a function call), rest lives on the left (in params or destructuring) - Copying, merging, or passing data? Use spread. Capturing extra args or remaining props? Use rest - Rest always returns an array, even when no extra elements are passed (returns `[]`) ### Quick Example ```javascript // Spread: unpacks array into separate elements const nums = [1, 2, 3]; const more = [...nums, 4, 5]; // [1, 2, 3, 4, 5] // Spread in a function call function add(a, b, c) { return a + b + c; } add(...nums); // 6 // Rest: collects remaining args into an array function sum(first, ...rest) { return first + rest.reduce((a, b) => a + b, 0); } sum(1, 2, 3, 4); // 10, rest = [2, 3, 4] ``` Context decides which one you get. Same three dots, different roles. ### Key Difference Spread appears on the right side of assignments or inside function calls. It breaks an iterable apart and gives you individual values. Rest appears on the left in function parameters or destructuring patterns. It gathers whatever is left over and wraps it in an array. One expands, the other compresses. ### When to Use - Copy an array without mutation: `[...arr]` - Merge objects: `{ ...obj1, ...obj2 }` - Pass an array as separate arguments to a function: `func(...arr)` - Capture a variable number of function arguments: `function fn(a, ...rest) {}` - Destructure with remaining properties: `const { x, ...rest } = obj` ### Comparison Table | Feature | Spread (`...`) | Rest (`...`) | |---|---|---| | Position | Right side (assignments, calls) | Left side (params, destructuring) | | Effect | Expands into individual elements | Collects remainders into array | | In functions | `func(...arr)` passes separate args | `func(a, ...rest)` gathers extra args | | Arrays | `[...arr1, ...arr2]` merges | `const [first, ...rest] = arr` splits | | Objects (ES2018+) | `{ ...obj1, ...obj2 }` merges | `const { a, ...rest } = obj` extracts | | When to use | Copy, merge, pass elements | Variable args, remaining props | ### How It Works JavaScript engines treat `...` as syntax sugar: spread iterates the source via `Symbol.iterator` (for arrays) or `Object.keys` (for objects), yielding values one by one. Rest scans the parameter list at call time and packages trailing arguments into a new array. Both create shallow copies, so nested objects share references with the original. In React codebases, spread is everywhere. The pattern `{ ...state, updatedField: newValue }` is how reducers stay immutable without pulling in extra libraries. ### Common Mistakes **Passing an array to a rest function without spreading it first:** ```javascript function add(...nums) { return nums.reduce((a, b) => a + b); } add([1, 2, 3]); // [1,2,3] becomes the first arg, returns NaN add(...[1, 2, 3]); // correct: 6 ``` **Assuming spread does a deep copy:** ```javascript const a = { nested: { x: 1 } }; const b = { ...a }; a.nested.x = 99; console.log(b.nested.x); // 99 - nested object is shared! // Fix: spread the nested object too const c = { ...a, nested: { ...a.nested } }; ``` **Spreading a non-iterable:** ```javascript [...42]; // TypeError: 42 is not iterable [...'abc']; // works: ['a', 'b', 'c'] - strings are iterable [...new Set([1, 2, 2])]; // works: [1, 2] - Set is iterable ``` **Rest must be the last parameter:** ```javascript function fn(a, ...rest, b) {} // SyntaxError function fn(a, ...rest) {} // correct ``` ### Real-World Usage - React: `<Button {...buttonProps} />` spreads props onto JSX elements - Redux reducers: `{ ...state, count: state.count + 1 }` for immutable updates - Express middleware: `{ ...req.query, filter: 'active' }` adds query params - Deduplication with Set: `[...new Set([1, 2, 2, 3])]` returns `[1, 2, 3]` ### Follow-up Questions **Q:** What does `const a = [1]; const b = [...a]; a.push(2); console.log(b);` output? **A:** `[1]`. Spread creates a new array, so `b` is independent of `a`. **Q:** What did developers use before object spread (ES2018)? **A:** `Object.assign({}, obj1, obj2)`. Babel still transpiles object spread to `Object.assign` for older build targets, so the output is identical. **Q:** What does rest return when no extra arguments are passed? **A:** An empty array `[]`. This is cleaner than the old `arguments` object, which was array-like but not a real array. **Q:** Can you spread a `Set` or `Map`? **A:** Yes, both are iterable. `[...new Set([1, 2, 2])]` gives `[1, 2]`. Useful for quick deduplication. **Q:** Why use rest parameters instead of the `arguments` object? **A:** `arguments` is array-like but not a real array, so `.map()` and `.reduce()` don't work on it directly. Rest gives you an actual array. Arrow functions also have no `arguments` of their own at all. ## Examples ### Merging User Settings ```javascript const defaults = { theme: 'light', fontSize: 14, showSidebar: true }; const userPrefs = { fontSize: 18, language: 'en' }; // Later keys override earlier ones const settings = { ...defaults, ...userPrefs }; // { theme: 'light', fontSize: 18, showSidebar: true, language: 'en' } ``` Order matters. `...userPrefs` comes second, so its `fontSize` overwrites the default. This pattern is standard in config merging and theme overrides. ### Variable Argument Logger ```javascript function log(level, ...messages) { const prefix = `[${level.toUpperCase()}]`; console.log(prefix, ...messages); // spread messages back out } log('info', 'User logged in', 'userId:', 42); // [INFO] User logged in userId: 42 ``` Rest collects `messages` into an array. Then spread passes them back as separate arguments to `console.log`. Rest in, spread out.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.