The three-dot operator ... serves two opposite roles: as SPREAD it expands an iterable into individual elements, and as REST it collects multiple elements into a single array or object.
Spread expands: [...arr1, ...arr2] merges arrays, {...obj1, ...obj2} merges objects (later keys win), fn(...args) passes array items as separate arguments, and [...arr] / {...obj} makes a SHALLOW copy. Rest gathers: function f(...args) collects all arguments into an array, and const [first, ...rest] = list or const { id, ...others } = obj captures the remainder. The distinguishing rule: rest appears on the LEFT of an assignment or in a parameter list (collecting); spread appears on the RIGHT or in a call/literal (expanding). A common gotcha is that spread copies are shallow — nested objects are still shared by reference.
Building a request payload from a base plus overrides: const payload = { ...defaults, ...testOverrides }; and cloning a fixture before mutating it: const copy = { ...fixture }; — though nested objects in the fixture are still shared, which can cause cross-test pollution.
What is the difference between spread and rest, and what does const merged = { ...a, ...b } do if a and b share a key?