Функциональное программирование (ФП) — это парадигма программирования, которая рассматривает вычисления как оценку математических функций и избегает изменения состояния и изменяемых данных. Основные принципы включают:
Чистая функция всегда возвращает один и тот же результат для одних и тех же входных данных и не имеет побочных эффектов. Это делает код более предсказуемым, тестируемым и легким для понимания.
Пример нечистой функции:
let discount = 0.1; // Внешнее состояние
function calculateDiscountedPrice(price) {
// Зависит от внешнего состояния `discount`
return price - price * discount;
}Пример чистой функции:
function calculateDiscountedPrice(price, discount) {
// Результат зависит только от аргументов
return price - price * discount;
}
console.log(calculateDiscountedPrice(100, 0.1)); // 90
console.log(calculateDiscountedPrice(100, 0.1)); // 90 (всегда тот же результат)Вместо того чтобы изменять объекты или массивы напрямую, в ФП принято создавать их копии с необходимыми изменениями. Это помогает избежать непреднамеренных побочных эффектов и упрощает отслеживание изменений состояния.
Пример с изменением (мутацией):
const user = { name: 'Алиса', age: 25 };
function celebrateBirthday(person) {
// Прямое изменение объекта (мутация)
person.age++;
return person;
}
celebrateBirthday(user);
console.log(user); // { name: 'Алиса', age: 26 } (исходный объект изменен)Пример с неизменяемостью:
const user = { name: 'Алиса', age: 25 };
function celebrateBirthday(person) {
// Создаем новый объект вместо изменения старого
return {
...person,
age: person.age + 1
};
}
const updatedUser = celebrateBirthday(user);
console.log(user); // { name: 'Алиса', age: 25 } (исходный объект нетронут)
console.log(updatedUser); // { name: 'Алиса', age: 26 } (возвращен новый объект)Функции высшего порядка — это функции, которые могут принимать другие функции в качестве аргументов или возвращать их в качестве результата. Это мощный инструмент для создания абстракций.
Пример:
Методы массивов, такие как map, filter и reduce, являются классическими примерами функций высшего порядка.
const numbers = [1, 2, 3, 4, 5];
// `filter` принимает функцию-предикат в качестве аргумента
const evenNumbers = numbers.filter(function(n) {
return n % 2 === 0;
});
console.log(evenNumbers); // [2, 4]
// Функция, которая возвращает другую функцию
function createMultiplier(factor) {
return function(number) {
return number * factor;
};
}
const double = createMultiplier(2);
const triple = createMultiplier(3);
console.log(double(5)); // 10
console.log(triple(5)); // 15Композиция позволяет строить сложные функции, объединяя простые. Это как конвейер: данные проходят через одну функцию, ее результат становится входными данными для следующей и так далее.
Пример:
Допустим, нам нужно взять строку, сделать ее заглавной и добавить восклицательный знак.
const toUpperCase = (str) => str.toUpperCase();
const addExclamation = (str) => `${str}!`;
// Вместо вложенных вызовов: addExclamation(toUpperCase('hello'))
// можно использовать композицию.
// Простая функция композиции
const compose = (f, g) => (x) => f(g(x));
const shout = compose(addExclamation, toUpperCase);
console.log(shout('hello world')); // 'HELLO WORLD!'В реальных проектах часто используются утилиты для композиции из библиотек, таких как Lodash или Ramda, которые позволяют объединять более двух функций.
Применение этих принципов делает код более декларативным (мы описываем, что нужно сделать, а не как), надежным и легко масштабируемым.