Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Поверхнева копія масиву». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**Поверхнева копія масиву, це новий масив з тими самими елементами верхнього рівня, і найчастіше її роблять через spread `[...arr]`.** Так само працюють `arr.slice()`, `Array.from(arr)` і `[].concat(arr)`: усі чотири повертають новий масив, тому `copy === arr` дає `false`. Але вкладені об'єкти та масиви копіюються за посиланням і залишаються спільними з оригіналом. ```javascript const copy = [...arr]; ``` **Ключове:** spread, `slice()`, `Array.from()` і `concat()` копіюють лише верхній рівень; для вкладених структур потрібна глибока копія, наприклад `structuredClone(arr)`.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**Поверхнева копія (shallow copy) масиву, це новий масив з власним посиланням, у який скопійовано елементи верхнього рівня.** Примітиви потрапляють у копію за значенням, а вкладені об'єкти та масиви, за посиланням, тому вони залишаються спільними з оригіналом. ## Теорія ### TL;DR - Поверхнева копія створює новий масив, тому `copy === arr` дає `false`, а зміни в копії не чіпають оригінал на верхньому рівні. - Найкоротший спосіб, spread: `const copy = [...arr]`. - Те саме роблять `arr.slice()`, `Array.from(arr)` і `[].concat(arr)`. - Усі вони копіюють лише верхній рівень: вкладені об'єкти й масиви лишаються спільними. - Заміна цілого елемента копії безпечна, зміна поля всередині вкладеного об'єкта, ні. - Для глибокої копії потрібен `structuredClone(arr)` або `JSON.parse(JSON.stringify(arr))`. ### Швидкий приклад ```javascript const arr = [1, 2, 3]; const copy = [...arr]; console.log(copy); // [1, 2, 3] console.log(copy === arr); // false (це новий масив) ``` ### Spread оператор Оператор розпакування `...` розкладає елементи масиву в новий літерал. Це найсучасніший і найкоротший запис, і саме його очікують почути на співбесіді. ```javascript const arr = [1, 2, 3]; const copy = [...arr]; console.log(copy); // [1, 2, 3] console.log(copy === arr); // false (новий масив) ``` Копія при цьому поверхнева: якщо елементами були об'єкти, вони й далі посилаються на ті самі дані. ```javascript const arr = [{ name: 'Tim' }]; const copy = [...arr]; copy[0].name = 'Alex'; console.log(arr[0].name); // "Alex", бо об'єкт спільний ``` ### slice(), Array.from() і concat() `slice()` без аргументів повертає новий масив, копію всього вихідного. Спосіб старий, але цілком надійний: ```javascript const arr = [1, 2, 3]; const copy = arr.slice(); console.log(copy); // [1, 2, 3] ``` `Array.from()` створює новий масив з ітерованого або масивоподібного значення: ```javascript const arr = [1, 2, 3]; const copy = Array.from(arr); console.log(copy); // [1, 2, 3] ``` Він корисний, коли потрібна не просто копія, а копія з перетворенням кожного елемента: ```javascript const doubled = Array.from(arr, x => x * 2); // [2, 4, 6] ``` `concat()` працює тому, що повертає новий масив, а не змінює вихідний: ```javascript const arr = [1, 2, 3]; const copy = [].concat(arr); console.log(copy); // [1, 2, 3] ``` ### Що залишається спільним Усі перелічені методи копіюють тільки верхній рівень. Якщо в масиві лежать об'єкти або вкладені масиви, вони залишаються за посиланням. ```javascript const arr = [[1, 2], [3, 4]]; const copy = [...arr]; copy[0][0] = 99; console.log(arr[0][0]); // 99, бо вкладений масив спільний ``` Натомість заміна цілого елемента копії оригінал не зачіпає, бо змінюється слот нового масиву, а не спільний об'єкт: ```javascript copy[0] = [7, 8]; console.log(arr[0]); // [99, 2], оригінал не змінився ``` ### Порівняння способів | Спосіб | Код | Створює новий масив | Глибока копія | | --- | --- | --- | --- | | Spread | `[...arr]` | Так | Ні | | `slice()` | `arr.slice()` | Так | Ні | | `Array.from()` | `Array.from(arr)` | Так | Ні | | `concat()` | `[].concat(arr)` | Так | Ні | Підсумок простий: щоб зробити поверхневу копію масиву, пишіть `const copy = [...arr];`. ### Глибоке копіювання Коли потрібно скопіювати ще й вкладені структури, поверхневої копії замало: ```javascript const deep = structuredClone(arr); ``` `structuredClone()` вбудований у сучасні браузери і Node.js, коректно обробляє `Map`, `Set`, `Date`, типізовані масиви та циклічні посилання, але не вміє копіювати функції. Старіший прийом `JSON.parse(JSON.stringify(arr))` простіший, проте втрачає `undefined` і функції, перетворює `Date` на рядок і кидає помилку на циклічних посиланнях. ### Типові помилки - Вважати, що `[...arr]` дає повністю незалежний масив: вкладені об'єкти лишаються спільними. - Плутати копіювання з присвоєнням: `const copy = arr` не створює масив, це те саме посилання. - Брати `JSON.parse(JSON.stringify(arr))` для масиву з `Date` чи функціями і дивуватися втраченим даним. - Думати, що `slice()` змінює масив: він повертає новий, на відміну від `splice()`, який змінює вихідний. - Копіювати масив ручним циклом з `push()` там, де достатньо одного виразу зі spread.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.