← Назад к вопросам

Почему ничего нельзя сделать с иммутабельными типами данных?

1.8 Middle🔥 171 комментариев
#JavaScript Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Почему ничего нельзя сделать с иммутабельными типами данных?

На самом деле это распространённое заблуждение. С иммутабельными (неизменяемыми) типами данных можно делать многое, просто они работают иначе, чем мутабельные (изменяемые).

Что такое иммутабельность?

Иммутабельность — это свойство объекта, которое не позволяет его изменять после создания. Попытка изменить иммутабельный объект не приведёт к изменению исходного значения, а создаст новый объект.

// Иммутабельные типы в JavaScript
const str = 'Hello';
const newStr = str.toUpperCase(); // Создает новую строку
console.log(str);    // 'Hello' (исходная не изменилась)
console.log(newStr); // 'HELLO'

// Примитивные типы по определению иммутабельны:
// string, number, boolean, null, undefined, Symbol, BigInt
const num = 42;
const newNum = num + 1; // Создается новое значение

Типы данных и их мутабельность

ТипМутабельностьПример
stringИммутабельна'hello'.replace('h', 'H') возвращает новую строку
numberИммутабельна5 + 3 создает новое число
booleanИммутабельнаtrue, false — константы
ArrayМутабельна[1,2,3][0] = 99 изменяет массив
ObjectМутабельнаobj.prop = 'new' изменяет объект
DateМутабельнаdate.setFullYear(2025) изменяет дату
SetМутабельнаset.add(1) изменяет множество
MapМутабельнаmap.set(key, value) изменяет карту

С иммутабельными данными МОЖНО делать

1. Трансформировать (создавать новые значения)

// Строки
const original = 'javascript';
const uppercase = original.toUpperCase();
const replaced = original.replace('java', 'type');
const sliced = original.slice(0, 4);

// Числа
const num = 42;
const doubled = num * 2;
const incremented = num + 1;
const absolute = Math.abs(-42);

// Можно создавать новые структуры данных
const arr = [1, 2, 3];
const newArr = [...arr, 4]; // Новый массив, исходный не изменился
const mapped = arr.map(n => n * 2); // Новый массив

2. Комбинировать (объединять значения)

// Конкатенация строк
const first = 'Hello';
const second = 'World';
const result = first + ' ' + second; // Новая строка

// Слияние массивов (без мутации)
const arr1 = [1, 2];
const arr2 = [3, 4];
const merged = [...arr1, ...arr2]; // Новый массив [1,2,3,4]

// Слияние объектов (без мутации)
const obj1 = { a: 1 };
const obj2 = { b: 2 };
const merged = { ...obj1, ...obj2 }; // { a: 1, b: 2 }

3. Фильтровать и отбирать

// Фильтрация массива
const numbers = [1, 2, 3, 4, 5];
const evens = numbers.filter(n => n % 2 === 0); // [2, 4]

// Поиск в строке
const text = 'JavaScript is awesome';
const hasJS = text.includes('Java'); // true

// Получение подстроки
const substring = text.substring(0, 4); // 'Java'

4. Выполнять вычисления

const prices = [10, 20, 30];
const total = prices.reduce((sum, price) => sum + price, 0); // 60
const average = total / prices.length; // 20

const name = 'John';
const length = name.length; // 4
const charCode = name.charCodeAt(0); // 74

Разница в подходах

Мутабельный подход (изменение исходного объекта)

const user = { name: 'John', age: 30 };
user.age = 31; // МУТАЦИЯ — изменяем исходный объект
user.city = 'NYC'; // МУТАЦИЯ
console.log(user); // { name: 'John', age: 31, city: 'NYC' }

Иммутабельный подход (создание новых значений)

const user = { name: 'John', age: 30 };
const updatedUser = { ...user, age: 31 }; // Новый объект
const withCity = { ...updatedUser, city: 'NYC' }; // Ещё новый объект

console.log(user);        // { name: 'John', age: 30 }
console.log(updatedUser); // { name: 'John', age: 31 }
console.log(withCity);    // { name: 'John', age: 31, city: 'NYC' }

Почему иммутабельность важна в React?

// Плохо: мутация состояния (React может не обнаружить изменение)
const [user, setUser] = useState({ name: 'John' });
user.name = 'Jane'; // ПЛОХО! Мутация

// Хорошо: создание нового объекта
const [user, setUser] = useState({ name: 'John' });
setUser({ ...user, name: 'Jane' }); // ХОРОШО!

// Плохо: мутация массива
const [items, setItems] = useState([1, 2, 3]);
items.push(4); // ПЛОХО!
setItems(items);

// Хорошо: создание нового массива
const [items, setItems] = useState([1, 2, 3]);
setItems([...items, 4]); // ХОРОШО!

Реакт полагается на сравнение ссылок. Если вы мутируете объект, ссылка остается той же, и Реакт может не обнаружить изменение.

Практические инструменты для работы с иммутабельностью

Immer (упрощает иммутабельную логику)

import produce from 'immer';

const user = { name: 'John', address: { city: 'NYC' } };

// С Immer можно писать как мутация, но она будет иммутабельной
const updatedUser = produce(user, draft => {
  draft.address.city = 'LA'; // Выглядит как мутация
});

console.log(user);        // { name: 'John', address: { city: 'NYC' } }
console.log(updatedUser); // { name: 'John', address: { city: 'LA' } }

Методы массивов для иммутабельной работы

const arr = [1, 2, 3];

// Иммутабельные методы
const added = arr.concat(4);          // Новый массив
const removed = arr.filter(n => n !== 2); // Новый массив
const mapped = arr.map(n => n * 2);   // Новый массив
const sliced = arr.slice(0, 2);       // Новый массив
const spliced = arr.toSpliced(1, 1);  // Новый массив (ES2023)

// Мутабельные методы (избегать в React)
arr.push(4);      // Изменяет исходный
arr.pop();        // Изменяет исходный
arr.reverse();    // Изменяет исходный
arr.sort();       // Изменяет исходный

Заключение

Симмутабельные типы данных не ограничивают функциональность — они просто работают по-другому. Вместо изменения исходного значения, вы создаёте новое. Это особенно важно в современной разработке фронтенда, где фреймворки вроде React полагаются на иммутабельность для отслеживания изменений и оптимизации производительности.

Алгоритм простой:

  • С примитивами: используй операции, которые возвращают новое значение
  • С объектами и массивами: используй spread-оператор (...) или методы, возвращающие новые объекты
  • В React: всегда создавай новые объекты при обновлении состояния