Spread & Rest in Depth
One syntax, two opposite jobs -- expanding values out and gathering them in.
Syntax
[...iterable] { ...object }
fn(...args)
function f(...rest) {}The same ... means opposite things depending on where it sits.
Spread -- expand outward
In array literals, object literals, and call arguments it unpacks an iterable or an object's own enumerable properties.
const merged = { ...defaults, ...overrides }; // later wins
const copy = [...list]; // shallow clone
Math.max(...numbers); // array to argsRest -- gather inward
In a parameter list or a destructuring pattern it collects the leftovers into a real array or object.
function log(first, ...others) {} // others is an array
const { id, ...rest } = record; // rest is everything elseThe catch
Both do a shallow copy. Nested objects are shared by reference, which is the number-one spread bug.
Example
Loading editor…
Press Run to execute the code.
When to use it
- Collect all extra keyword arguments into a rest parameter object in a variadic logger function.
- Spread a config override object into a defaults object to merge settings without mutation.
- Spread an array of IDs into a SQL IN clause template string helper.
More examples
Rest parameters in a function
Collects all arguments after level into a rest array so any number of messages can be logged.
function log(level, ...messages) {
messages.forEach(m => console.log(`[${level}] ${m}`));
}
log("INFO", "Server started", "Listening on port 3000");Spread to merge objects
Merges defaults and overrides into a new object; later spread keys overwrite earlier ones.
const defaults = { timeout: 5000, retries: 3, debug: false };
const overrides = { retries: 5, debug: true };
const config = { ...defaults, ...overrides };
console.log(config);Spread args from array
Spreads an array as individual positional arguments for functions that do not accept an array.
function sum(a, b, c) { return a + b + c; }
const args = [1, 2, 3];
console.log(sum(...args)); // 6
console.log(Math.min(...[8, 2, 5, 1])); // 1
Discussion