Иммутабельность, каррирование и композиция

Понятия из функционального стиля, которые любят спрашивать «на понимание».

Иммутабельность — подход, при котором данные не меняют, а создают их новую версию. Это упрощает отслеживание изменений и предотвращает «неожиданные» мутации.

Мутация против иммутабельного обновления

Мутирующие методы (push, splice, присваивание свойств) меняют исходные данные. Иммутабельный подход возвращает новый объект/массив, не трогая старый.

const state = { count: 1, items: ["a"] };

// иммутабельно: новый объект через spread
const next = { ...state, count: 2 };

console.log(state.count); // старое не изменилось
console.log(next.count);
console.log(state === next);

Вывод:

1
2
false

Иммутабельные методы массива

map, filter, concat, slice, spread — не мутируют. push, splice, sort — мутируют. Это важно помнить, чтобы случайно не испортить общий массив.

const arr = [3, 1, 2];

const sortedCopy = [...arr].sort(); // сначала копия, потом sort
console.log(sortedCopy);
console.log(arr);                   // оригинал цел

const without2 = arr.filter((x) => x !== 2); // новый массив
console.log(without2);
console.log(arr);

Вывод:

[ 1, 2, 3 ]
[ 3, 1, 2 ]
[ 3, 1 ]
[ 3, 1, 2 ]

Object.freeze: запрет на мутацию

Object.freeze делает объект неизменяемым на верхнем уровне: попытки изменить свойства молча игнорируются (в нестрогом режиме).

const config = Object.freeze({ debug: false });
config.debug = true;      // игнорируется
console.log(config.debug);
console.log(Object.isFrozen(config));

Вывод:

false
true

Каррирование

Каррирование — превращение функции от нескольких аргументов в цепочку функций по одному аргументу. Помогает «частично применять» функцию.

const add = (a) => (b) => (c) => a + b + c;

console.log(add(1)(2)(3));
const add10 = add(10);       // зафиксировали первый аргумент
console.log(add10(20)(30));

Вывод:

6
60

Композиция функций

Композиция объединяет несколько функций в одну: выход одной становится входом следующей.

const compose = (...fns) => (x) =>
  fns.reduceRight((acc, fn) => fn(acc), x);

const inc = (n) => n + 1;
const double = (n) => n * 2;

const incThenDouble = compose(double, inc); // сначала inc, потом double
console.log(incThenDouble(5)); // (5+1)*2

Вывод:

12

Итог

  • Иммутабельность — не менять данные, а создавать их новую версию.
  • map/filter/spread не мутируют; push/sort/splice — мутируют.
  • Каррирование разбивает аргументы по одному; композиция соединяет функции в конвейер.
Проверьте себя
1. Что такое иммутабельность?
AЗапрет создавать объекты
BПодход, при котором данные не меняют, а создают их новую версию
CУскорение кода
DУдаление переменных
2. Какой метод массива НЕ мутирует исходный массив?
Apush
Bsplice
Cfilter
Dsort
3. Что такое каррирование?
AСортировка массива
BПревращение функции от нескольких аргументов в цепочку функций по одному аргументу
CУдаление аргументов функции
DСпособ объявить класс
Поддержать проект