Skip to main content

Immutable та mutable дані

Mutable (змінювані) дані можна змінити після створення, а immutable (незмінні) дані змінити не можна, замість цього створюється нове значення. У JavaScript примітиви незмінні, а об'єкти, масиви й функції змінювані.

Теорія

TL;DR

  • Mutable, об'єкт можна редагувати після створення: object, array, function, Map, Set.
  • Immutable, значення редагувати не можна, лише створити нове: усі примітиви.
  • const фіксує посилання, а не вміст об'єкта, тому const user = {} усе одно дозволяє user.name = '...'.
  • «Зміна» рядка чи числа завжди створює нове значення, старе лишається недоторканим.
  • Object.freeze() робить об'єкт незмінним на верхньому рівні, для вкладених потрібен deep freeze.

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

javascript
// mutable const user = { name: 'Tim' }; user.name = 'Alex'; console.log(user); // { name: 'Alex' } // immutable let a = 'Hello'; a[0] = 'J'; console.log(a); // "Hello", нічого не змінилося

Визначення

ТермінПерекладСуть
Mutableзмінюванийоб'єкт, який можна змінювати після створення
Immutableнезміннийдані, які змінити не можна, можна лише створити нові

Змінювані (mutable) дані

Об'єкти та масиви в JavaScript, це змінювані структури.

javascript
const user = { name: 'Tim' }; user.name = 'Alex'; // змінюємо об'єкт console.log(user); // { name: 'Alex' }

Хоча змінну user оголошено через const, її вміст (об'єкт) можна змінити, адже const забороняє міняти саме посилання, а не дані, на які воно вказує.

Те саме з масивом:

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

Масиви mutable, бо ми можемо додавати, видаляти й змінювати елементи.

Незмінні (immutable) дані

Примітиви в JavaScript незмінні. До них належать: string, number, boolean, null, undefined, symbol, bigint.

javascript
let a = 'Hello'; a[0] = 'J'; // спроба змінити рядок console.log(a); // "Hello", не змінилося

Рядки immutable: під час «зміни» створюється новий рядок.

Те саме з числами:

javascript
let x = 5; let y = x; y = y + 1; console.log(x); // 5 console.log(y); // 6

Числа теж immutable, їх не можна «поміняти», можна лише створити нове значення.

Як це виглядає в пам'яті:

Тип данихЗмінюваністьДе зберігаєтьсяПоведінка
Примітив (string, number, boolean та інші)ImmutableStackпід час «зміни» створюється нове значення
Об'єкт, масив, функціяMutableHeapзмінюється за посиланням
javascript
let name = 'Ann'; name = name + 'a';
text
STACK: +------------------+ | name = "Ann" | <- старий рядок | name = "Anna" | <- новий рядок (створений заново) +------------------+

Рядок "Ann" не змінюється, створюється новий рядок "Anna".

Чому це важливо

Перше, поведінка під час копіювання:

javascript
const user1 = { name: 'Tim' }; const user2 = user1; user2.name = 'Alex'; console.log(user1.name); // "Alex", змінилися обидва (mutable)

Друге, реактивні фреймворки (React, Redux, Vue та інші). Незмінність там ключовий принцип:

  • дозволяє відстежувати зміни стану через порівняння посилань;
  • полегшує відкат змін (undo/redo);
  • робить код передбачуванішим.

Приклад підходу React:

javascript
// погано (мутуємо стан напряму) state.user.age++; // добре (незмінний апдейт) setState({ ...state, user: { ...state.user, age: state.user.age + 1 } });

Як зробити об'єкт незмінним вручну

javascript
const user = Object.freeze({ name: 'Tim', age: 25 }); user.age = 30; // не спрацює console.log(user.age); // 25

Object.freeze() робить об'єкт immutable на верхньому рівні. Для вкладених властивостей потрібно «заморожувати глибоко»:

javascript
function deepFreeze(obj) { Object.keys(obj).forEach(key => { if (typeof obj[key] === 'object' && obj[key] !== null) { deepFreeze(obj[key]); } }); return Object.freeze(obj); } const data = deepFreeze({ user: { name: 'Tim', skills: ['JS'] } }); data.user.name = 'Alex'; // не зміниться

Підсумкова таблиця:

КатегоріяПрикладиЗмінюваністьПоведінка
Immutable (незмінні)string, number, boolean, null, undefined, symbol, bigintне можна змінитистворюється нова копія
Mutable (змінювані)object, array, function, Map, Setможна змінитизмінюються «на місці»

Коротко:

  • Immutable, змінити не можна, тільки створити нове значення.
  • Mutable, можна змінити «на місці».
  • Примітиви immutable, об'єкти та масиви mutable.
  • Незмінність робить код надійнішим, особливо в React і Redux.

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

  • Плутати const з незмінністю. const про перепризначення змінної, а не про вміст об'єкта.
  • Думати, що Object.freeze() захищає всю структуру. Він поверхневий, вкладені об'єкти лишаються змінюваними.
  • Не помічати, що в non-strict режимі запис у заморожений об'єкт тихо ігнорується, а в 'use strict' кидає TypeError.
  • Мутувати стан у React (state.items.push(x)) і дивуватися, чому компонент не перемалювався: порівняння за посиланням не бачить різниці.
  • Вважати, що методи масиву незмінні. push, splice, sort, reverse мутують оригінал; незмінні аналоги, це concat, slice, toSorted, toReversed.

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

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

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