In an array literal or a function call, ... is spread: it expands an iterable into elements or arguments. In a destructuring pattern or parameter list it is rest: it gathers the remaining values into a new array. Object spread and rest (Object Destructuring) copy own enumerable properties instead of iterating.
const nums = [...new Set([3, 1, 3, 2])]; // spread an iterable: dedupe
const [head, ...tail] = nums; // rest collects the remainder
console.log(nums, head, tail, Math.max(...nums), [...'hi', ...tail]);
const tree = [
{ id: 1, children: [] },
{ id: 2, children: [{ id: 3, children: [{ id: 4, children: [] }] }] },
];
const flatten = ({ children, ...node }) => [node, ...children.flatMap(flatten)]; // rest, spread
console.log(tree.flatMap(flatten));[ 3, 1, 2 ] 3 [ 1, 2 ] 3 [ 'h', 'i', 1, 2 ]
[ { id: 1 }, { id: 2 }, { id: 3 }, { id: 4 } ]A rest element must be last: const [...init, last] = arr is a SyntaxError, as for rest parameters (Parameters).
Spread needs an iterable, so an array-like { length: 2 } throws TypeError; use Array.from() for it.
Math.max(...big) throws RangeError for very large arrays (Mutator Methods); reduce() scales.