Три крапки ... означають протилежні речі залежно від місця:
- spread (розгортання) - «розкласти» масив чи об'єкт на окремі елементи. Стоїть там, де використовують значення;
- rest (решта) - «зібрати» кілька елементів в один масив чи об'єкт. Стоїть там, де оголошують змінні чи параметри.
Spread:
// масиви
const all = [...frontend, ...backend]; // об'єднання
const copy = [...items]; // поверхнева копія
Math.max(...prices); // масив як аргументи функції
const unique = [...new Set(tags)]; // будь-який ітерований об'єкт у масив
// об'єкти
const defaults = { perPage: 20, sort: 'name' };
const options = { ...defaults, ...userOptions }; // пізніші властивості перекривають ранніші
const updated = { ...user, name: 'Іра' }; // копія зі зміненим полем
Rest:
function log(level, ...messages) {} // решта аргументів у масив
const [first, ...others] = list; // решта елементів
const { password, ...safeUser } = user; // усе, крім password
Останній приклад - зручний спосіб прибрати поле з об'єкта без мутації.
Що варто знати про spread:
- копія поверхнева. Вкладені об'єкти й масиви лишаються спільними:
const copy = { ...settings };
copy.limits.upload = 1; // змінило й settings.limits
Для глибокої копії - structuredClone(settings).
- порядок важливий:
{ ...user, role: 'admin' }перезапише роль, а{ role: 'admin', ...user }- ні, якщо вuserвона є; - spread об'єкта копіює лише власні перелічувані властивості - без прототипу, гетери обчислюються в значення. Тому
{ ...dateInstance }чи{ ...classInstance }дасть простий об'єкт без методів; - spread
nullчиundefinedв об'єкті нічого не додає (зручно для умовних полів:{ ...(isAdmin && { role: 'admin' }) }), а в масиві - кидаєTypeError; - дуже великі масиви як аргументи (
Math.max(...hugeArray)на сотні тисяч елементів) можуть перевищити ліміт аргументів - для нихreduce.
Spread - основа незмінних оновлень стану у React, Pinia, Redux: замість зміни об'єкта створюється новий з потрібними змінами.
У PHP ті самі три крапки: ...$args у параметрах (rest) і [...$a, ...$b] чи f(...$args) (spread).