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

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

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

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

Мутирующие методы (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. Какой метод массива НЕ мутирует исходный массив?
Afilter
Bpush
Csplice
Dsort
3. Что такое каррирование?
AСортировка массива
BПревращение функции от нескольких аргументов в цепочку функций по одному аргументу
CУдаление аргументов функции
DСпособ объявить класс