Detailed explanation
Spread and rest both use the three-dot syntax (`...`), but they move data in opposite directions. Spread expands values into a surrounding expression, while rest collects values into a variable. For example, `const merged = { ...a, ...b };` spreads properties into a new object, whereas `function sum(...nums) { return nums.reduce((s, n) => s + n, 0); }` gathers arguments into an array. Technically, these are syntax forms rather than one general-purpose operator; their meaning depends on where they appear.
Spread works in function calls, array literals, and object literals. In `Math.max(...scores)`, it supplies iterable values as separate arguments; in `[...scores, 4]`, it inserts them into a new array. These two contexts require an iterable, such as an array, string, or set. Object spread behaves differently: `{ ...source }` copies the source’s own enumerable properties, including enumerable symbol properties, into a new object. It does not require the source to be iterable. When property names overlap, later entries win, so `{ ...a, ...b }` uses `b`’s value for shared keys.
Rest appears in function parameter lists and destructuring patterns. In `function log(first, ...others) {}`, `others` is a real array containing arguments after the first. In `const [head, ...tail] = items;`, `tail` contains the remaining iterable values. In `const { id, ...details } = user;`, `details` receives the remaining own enumerable properties not selected by the pattern. A rest parameter or destructuring rest element must come last and cannot have a trailing comma. Unlike the older `arguments` object, a rest parameter supports array methods directly and excludes arguments matched by earlier parameters.
This distinction matters when combining data, writing flexible functions, or extracting selected fields. Both spread copies and destructuring rest collections are shallow: nested objects remain shared references rather than independent copies. Interviewers usually check whether you can identify the syntax from its context, explain array versus object behaviour, and recognise these copying limits. A useful rule is that spread expands data where values are supplied, while rest gathers data where parameters or assignment targets receive it.
Key points to remember
- Spread expands values; rest collects values into an array or object.
- Function-call and array spread require iterables; object spread copies own enumerable properties.
- Rest is used in function parameters and array or object destructuring.
- Rest must appear last; spread can appear multiple times among other entries.
- Copies are shallow, and later object properties overwrite earlier properties with the same key.
Common mistakes candidates make
- Assuming a plain object can be spread into an array or function call without being iterable.
- Claiming spread creates a deep copy, so changing a nested object cannot affect the original.
- Putting another parameter or destructuring entry after rest, such as `function f(...args, last) {}`.
Likely follow-up questions
How is a rest parameter different from arguments?
A rest parameter is a real array containing only the arguments not matched by earlier parameters. The `arguments` object is array-like and contains all supplied arguments; arrow functions do not have their own `arguments`, but can declare rest parameters.
Does object spread create an independent copy?
It creates a new outer object, but nested objects retain their original references. Reassigning a top-level property on the copy does not change the original, while mutating a shared nested object affects both.
Can spread and rest be used together?
Yes: in `function sum(...nums) { return nums.reduce((s, n) => s + n, 0); }`, the parameter uses rest. Calling `sum(...[1, 2, 3])` uses spread to supply three arguments, which rest then collects into `nums`.
Interview tip: Start with “spread expands, rest collects,” show one example of each, and then mention the shallow-copy limitation.
