Three dots before a variable, and its contents pour out right where you wrote them. It is one of the few additions to the language that changed how code gets written day to day, especially in interfaces.
Definition
Spread, written with three dots, expands the contents of an iterable, array or string, or the properties of an object, at the exact spot where it appears. It always reads like an opening: where there was a box, there are now its contents.
const base = [1, 2];
console.log([0, ...base, 3]); // [0, 1, 2, 3]
console.log([..."abc"]); // ["a", "b", "c"]
const defaults = { size: "M", color: "black" };
console.log({ ...defaults, color: "red" });
// { size: "M", color: "red" }That last line shows the behavior to remember on objects: with an identical key, the last write wins. This ordering is what makes it possible to merge default values with supplied ones.
Three uses that come up every day
| Use | Form |
|---|---|
| Copy without touching the original | const copy = [...list] |
| Merge two objects | { ...defaults, ...options } |
| Pass an array as arguments | Math.max(...scores) |
The first row matters most. Plenty of methods modify the original array, which breaks everything in an interface where the previous value serves as a point of comparison. Copy first, transform second, has become the default reflex.
const scores = [12, 18, 9];
// Sort without damaging the original array
const sorted = [...scores].sort((a, b) => a - b);
console.log(sorted); // [9, 12, 18]
console.log(scores); // [12, 18, 9], untouchedSpread also removes duplicates in one line, paired with a Set: [...new Set(list)]. The set refuses repeats, and the three dots turn it back into an array.
Its limit: the copy stays shallow
This is the classic trap, and it only shows up on nested data.
const source = { profile: { city: "Lyon" } };
const copy = { ...source };
copy.profile.city = "Paris";
console.log(source.profile.city); // "Paris": the original changed tooThree dots copy the first level only. The nested object is not duplicated, the same memory address gets copied across, so both variables point at it. For a full copy, use structuredClone(source), available in every recent environment.
Frequently asked questions
How does it differ from rest, written the same way?
By position in the line, and nothing else. The same three dots spread contents when used on the right of an assignment or inside a call, and gather values when they appear in a parameter list or on the left of an assignment. The subject is covered in Rest (...).
Can null or undefined be spread?
Inside an object, yes: { ...null } simply yields an empty object, no error. Inside an array, no: [...null] throws a type error, because emptiness is not iterable. It is a surprising asymmetry, and it explains a few crashes on incomplete data.
Why does it show up everywhere in React?
Because a component's state must never be modified in place: a new object has to be supplied for the display to refresh. Three dots produce that copy in one readable expression. Our React course spends real time on this principle, which explains half the rendering bugs beginners hit.