Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Чому оператор = не копіює об'єкт». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**Оператор `=` не копіює об'єкт, він копіює лише посилання на нього в пам'яті, тому обидві змінні вказують на один і той самий об'єкт.** Причина в тому, що примітиви (`number`, `string`, `boolean`, `null`, `undefined`, `symbol`, `bigint`) присвоюються за значенням, а об'єкти, масиви, функції, `Map` і `Set`, за посиланням. Через це зміна «копії» змінює й оригінал. Щоб отримати справжню копію, потрібен spread `{ ...obj }` чи `Object.assign({}, obj)` для верхнього рівня, або `structuredClone(obj)` чи `_.cloneDeep(obj)` для глибокої копії. ```javascript const user = { name: 'Alice' }; const clone = user; // не копія, а друге посилання clone.name = 'Oleh'; console.log(user.name); // 'Oleh' console.log(clone.name); // 'Oleh' ``` **Ключове:** `=` створює ще одне ім'я для того самого об'єкта, а не новий об'єкт.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**Оператор `=` не копіює об'єкт, а лише копіює посилання на нього в пам'яті, тому обидві змінні вказують на один і той самий об'єкт.** Саме через це «копія» не є незалежною: будь-яка зміна через одну змінну одразу видима через іншу. ## Теорія ### TL;DR - `=` для об'єкта копіює **посилання**, а не вміст. - Обидві змінні після `const clone = user` вказують на **один об'єкт у пам'яті**. - Примітиви присвоюються **за значенням**, об'єкти, масиви й функції, **за посиланням**. - Тому зміна «копії» змінює й оригінал. - Для поверхневої копії беріть `{ ...obj }` або `Object.assign({}, obj)`. - Для глибокої копії беріть `structuredClone(obj)` або `_.cloneDeep(obj)`. ### Швидкий приклад ```javascript const user = { name: 'Alice' }; const clone = user; // «копіюємо» об'єкт clone.name = 'Oleh'; console.log(user.name); // 'Oleh' console.log(clone.name); // 'Oleh' ``` Зміна в `clone` змінила й `user`, бо **це один і той самий об'єкт у пам'яті**. ## Як це виглядає «під капотом» ```text Пам'ять: +---------------------+ | { name: 'Alice' } | +----------+----------+ ^ | +-- user +-- clone ``` І `user`, і `clone`, це **посилання** на один і той самий об'єкт. Коли ви пишете `const clone = user`, створюється **ще одне посилання**, а не нова копія. Сам об'єкт лежить у купі (heap) в одному екземплярі, а змінні тримають лише адресу. ## Чому так відбувається У JavaScript є два типи даних за способом присвоєння: | Тип даних | Як копіюється | | --- | --- | | **Примітиви** (`number`, `string`, `boolean`, `null`, `undefined`, `symbol`, `bigint`) | за значенням | | **Посилальні** (`object`, `array`, `function`, `Map`, `Set` тощо) | за посиланням | ```javascript let a = 5; let b = a; b = 10; console.log(a); // 5, копія значення const obj1 = { x: 1 }; const obj2 = obj1; obj2.x = 2; console.log(obj1.x); // 2, спільне посилання ``` Зверніть увагу: `const` тут не рятує. `const` забороняє переприсвоїти саму змінну, але не забороняє змінювати вміст об'єкта, на який вона вказує. ## Якщо потрібна саме копія Використайте один зі способів: | Що потрібно | Як зробити | | --- | --- | | Поверхнева копія | `{ ...obj }` або `Object.assign({}, obj)` | | Глибока копія | `structuredClone(obj)` або `_.cloneDeep(obj)` | Приклад: ```javascript const user = { name: 'Alice' }; const clone = { ...user }; // створює новий об'єкт clone.name = 'Oleh'; console.log(user.name); // "Alice" console.log(clone.name); // "Oleh" ``` Тепер об'єкти **незалежні**. ## Підсумкова таблиця | Що відбувається при `const b = a` | Пояснення | | --- | --- | | Примітиви (числа, рядки тощо) | Копіюється **значення** | | Об'єкти, масиви, функції | Копіюється **посилання**, а не вміст | | Зміна копії впливає на оригінал | Так, якщо це об'єкт | | Як уникнути | Використовуйте spread (`{ ...obj }`) або `structuredClone()` | ### Типові помилки - **Вважати, що `const` захищає об'єкт від змін.** `const` фіксує лише прив'язку змінної, вміст об'єкта залишається мутабельним. - **Порівнювати об'єкти через `===` і чекати порівняння за вмістом.** `{ x: 1 } === { x: 1 }` дає `false`, бо порівнюються посилання, а `user === clone` після `=` дає `true`. - **Передавати об'єкт у функцію і мутувати його там.** Аргумент, це те саме посилання, тому виклик змінює об'єкт у місці виклику. - **Робити `const copy = state` у React або Redux.** Посилання не змінюється, тому перемальовування не відбувається, а стан мутується напряму. - **Зупинятися на spread для вкладених структур.** `{ ...obj }` копіює лише верхній рівень, вкладені об'єкти й далі спільні.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.