Чому оператор = не копіює об'єкт
Оператор = не копіює об'єкт, а лише копіює посилання на нього в пам'яті, тому обидві змінні вказують на один і той самий об'єкт. Саме через це «копія» не є незалежною: будь-яка зміна через одну змінну одразу видима через іншу.
Теорія
TL;DR
=для об'єкта копіює посилання, а не вміст.- Обидві змінні після
const clone = userвказують на один об'єкт у пам'яті. - Примітиви присвоюються за значенням, об'єкти, масиви й функції, за посиланням.
- Тому зміна «копії» змінює й оригінал.
- Для поверхневої копії беріть
{ ...obj }абоObject.assign({}, obj). - Для глибокої копії беріть
structuredClone(obj)або_.cloneDeep(obj).
Швидкий приклад
const user = { name: 'Alice' };
const clone = user; // «копіюємо» об'єкт
clone.name = 'Oleh';
console.log(user.name); // 'Oleh'
console.log(clone.name); // 'Oleh'Зміна в clone змінила й user, бо це один і той самий об'єкт у пам'яті.
Як це виглядає «під капотом»
Пам'ять:
+---------------------+
| { name: 'Alice' } |
+----------+----------+
^
|
+-- user
+-- cloneІ user, і clone, це посилання на один і той самий об'єкт. Коли ви пишете const clone = user, створюється ще одне посилання, а не нова копія. Сам об'єкт лежить у купі (heap) в одному екземплярі, а змінні тримають лише адресу.
Чому так відбувається
У JavaScript є два типи даних за способом присвоєння:
| Тип даних | Як копіюється |
|---|---|
Примітиви (number, string, boolean, null, undefined, symbol, bigint) | за значенням |
Посилальні (object, array, function, Map, Set тощо) | за посиланням |
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) |
Приклад:
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 }копіює лише верхній рівень, вкладені об'єкти й далі спільні.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.