Skip to main content

Чому оператор = не копіює об'єкт

Оператор = не копіює об'єкт, а лише копіює посилання на нього в пам'яті, тому обидві змінні вказують на один і той самий об'єкт. Саме через це «копія» не є незалежною: будь-яка зміна через одну змінну одразу видима через іншу.

Теорія

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 } копіює лише верхній рівень, вкладені об'єкти й далі спільні.

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.