Spread / Rest
В одной фразе: … в позиции значения — это spread (разворачивает iterable), в позиции параметра/остатка — это rest (собирает в Array). Ключевой собеседовательный вопрос: почему spread объектов — shallow copy, и чем он отличается от глубокого клонирования.
// Spread объектов: shallow copy — вложенные объекты не копируютсяconst original = { a: 1, nested: { b: 2 } };const clone = { ...original, c: 3 }; // { a:1, nested:{b:2}, c:3 }
clone.a = 99; // не затрагивает originalclone.nested.b = 99; // МУТИРУЕТ original.nested!console.log(original.nested.b); // 99 — shallow copy!
// Последнее свойство побеждает при конфликте:const merged = { ...{ x: 1, y: 1 }, ...{ x: 2 } }; // { x:2, y:1 }// Rest параметры: заменяют arguments, работают со стрелкамиfunction log(level, ...messages) { // messages — настоящий Array messages.forEach(m => console.log(`[${level}] ${m}`));}log('INFO', 'start', 'ready', 'done'); // три строки в лог
// arguments — псевдомассив, только в обычных функциях// rest — полноценный Array, всегда последний параметрconst sum = (...nums) => nums.reduce((a, b) => a + b, 0);sum(1, 2, 3, 4); // 10// Spread с iterable: Set, Map, String, generatorsconst unique = [...new Set([1, 1, 2, 3, 2])]; // [1, 2, 3]const chars = [..."hello"]; // ['h','e','l','l','o']
// Spread вместо apply:const nums = [3, 1, 4, 1, 5];Math.max(...nums); // 5 — вместо Math.max.apply(null, nums)
// Глубокое клонирование: spread НЕ подходит// Правильные способы:const deep1 = structuredClone(original); // ES2022, обрабатывает циклические ссылкиconst deep2 = JSON.parse(JSON.stringify(original)); // только JSON-safe данныеИтог: Spread создаёт поверхностную копию: примитивные свойства дублируются, ссылки — нет. Rest-параметры всегда последние, возвращают настоящий Array.