Skip to main content

Передача за значенням і за посиланням

«За значенням» означає, що змінна зберігає саме значення, і під час копіювання створюється нова незалежна копія даних; «за посиланням» означає, що змінна зберігає лише вказівник на місце в пам'яті, і копіюється саме цей вказівник. У JavaScript за значенням поводяться примітиви, а за посиланням, об'єкти та всі складні структури даних.

Теорія

TL;DR

  • Примітиви (number, string, boolean, null, undefined, symbol, bigint) передаються за значенням.
  • Об'єкти (object, array, function, Date, Map, Set тощо) передаються за посиланням.
  • Копія примітива повністю незалежна: зміна b не впливає на a.
  • Копія об'єкта, це та сама структура в пам'яті: зміна через одну змінну видно через іншу.
  • Щоб отримати незалежний об'єкт, потрібна поверхнева ({ ...obj }) або глибока копія.

Швидкий приклад

javascript
// за значенням let a = 5; let b = a; // копіюється значення 5 b = 10; console.log(a); // 5, не змінився console.log(b); // 10 // за посиланням const user1 = { name: 'Maria' }; const user2 = user1; // копіюється ПОСИЛАННЯ, а не сам об'єкт user2.name = 'Alex'; console.log(user1.name); // "Alex" console.log(user2.name); // "Alex"

Що означає «за значенням» (by value)

Змінна зберігає саме значення, а не посилання на нього. Під час копіювання створюється нова незалежна копія даних.

За значенням передаються примітиви (прості типи даних). До них належать:

  • number
  • string
  • boolean
  • null
  • undefined
  • symbol
  • bigint
javascript
let a = 5; let b = a; // копіюється значення 5 b = 10; console.log(a); // 5 <- не змінився console.log(b); // 10

a і b тепер два незалежні значення, і зміна b не впливає на a.

Що означає «за посиланням» (by reference)

Змінна не зберігає сам об'єкт, вона зберігає посилання (вказівник) на місце в пам'яті, де цей об'єкт лежить.

За посиланням передаються всі об'єкти та складні структури даних:

  • object
  • array
  • function
  • Date, Map, Set і так далі
javascript
const user1 = { name: 'Maria' }; const user2 = user1; // копіюється ПОСИЛАННЯ, а не сам об'єкт user2.name = 'Alex'; console.log(user1.name); // "Alex" console.log(user2.name); // "Alex"

Обидві змінні вказують на один і той самий об'єкт у пам'яті, тому зміна user2 змінює і user1.

Візуально це виглядає так:

text
+------------+ | user1 | --+ +------------+ | v { name: "Maria" } ^ +------------+ | | user2 | --+ +------------+

Приклад з масивом

Масив, це теж об'єкт, тож для нього діє те саме правило:

javascript
const arr1 = [1, 2, 3]; const arr2 = arr1; arr2.push(4); console.log(arr1); // [1, 2, 3, 4] console.log(arr2); // [1, 2, 3, 4]

Обидва масиви, це один і той самий об'єкт у пам'яті.

Як створити копію об'єкта і не тягнути посилання

Якщо потрібен новий незалежний об'єкт, дані треба явно скопіювати.

Поверхнева копія (spread):

javascript
const user1 = { name: 'Tim', age: 25 }; const user2 = { ...user1 }; // оператор spread user2.name = 'Alex'; console.log(user1.name); // "Tim" console.log(user2.name); // "Alex"

Глибока копія (для вкладених об'єктів):

javascript
const user1 = { name: 'Tim', address: { city: 'Kyiv' } }; const user2 = JSON.parse(JSON.stringify(user1)); // глибоке клонування user2.address.city = 'Lviv'; console.log(user1.address.city); // "Kyiv" console.log(user2.address.city); // "Lviv"

Стек, купа і підсумкові таблиці

ТипДе зберігаєтьсяЩо відбувається під час копіювання
Примітив (by value)у стеку (stack)створюється нова копія
Об'єкт (by reference)у купі (heap)копіюється посилання на те саме місце
Тип данихПередачаПриклад
---------
string, number, boolean, null, undefined, symbol, bigintза значеннямlet a = 5; let b = a;
object, array, function, Date, Map, Setза посиланнямlet obj2 = obj1;

Коротко:

  • За значенням створюється копія даних.
  • За посиланням копіюється вказівник на той самий об'єкт.
  • Саме тому зміна одного об'єкта впливає на інший, якщо вони пов'язані посиланням.

Типові помилки

  • Вважати, що const захищає вміст об'єкта. const забороняє перепризначити змінну, але не забороняє змінювати поля об'єкта, на який вона вказує.
  • Робити const copy = original для об'єкта і думати, що це копія. Це друга назва для того самого об'єкта.
  • Плутати поверхневу копію з глибокою: { ...user } копіює лише верхній рівень, вкладені об'єкти залишаються спільними.
  • Використовувати JSON.parse(JSON.stringify(obj)) бездумно: цей спосіб втрачає undefined, функції, Symbol, перетворює Date на рядок і ламається на циклічних посиланнях. Для складних випадків краще structuredClone(obj).
  • Порівнювати об'єкти через === і чекати true: { a: 1 } === { a: 1 } дає false, бо це два різні посилання.

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

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

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