Чистые функции — строительные блоки в функциональном программировании. Их обожают за простоту и тестируемость.
В этой статье вы найдете чек-лист, который поможет определить чистая функция или нет.
Функция должна удовлетворять двум условиям, чтобы считаться «чистой»:
— Каждый раз функция возвращает одинаковый результат, когда она вызывается с тем же набором аргументов
— Нет побочных эффектов
Рассмотрим подробнее.
Сравните это:
С этим:
В первом случае значение возвращается на основании заданных параметров, независимо от того, где/когда вы его вызываете.
Если вы сложите 2 и 4, всегда получите 6.
Ничего не влияет на результат.
Нечистые функции = непостоянные результаты
Второй пример ничего не возвращает. Он полагается на общее состояние для выполнения своей работы путем увеличения переменной за пределами своей области.
Эта модель кошмар для разработчиков.
Разделяемое состояние вводит зависимость от времени. Вы получаете разные результаты в зависимости от того, когда вы вызвали функцию. В первый раз результат 6, в следующий раз 10 и так далее.
Что лучше?
В каком случае вы получите меньше багов, которые появляются только при определенных условиях?
В каком случае с большей вероятностью вы преуспеете в многопоточной среде, где временные зависимости могут сломать систему?
Определенно в первом.
Этот тест сам по себе контрольный список.
Примеры побочных эффектов:
По сути, любая работа, выполняемая функцией, не связана с вычислением конечного результата.
Советую посмотреть видео Боба Мартина.
Вот “нечистая” функция с побочным эффектом.
console.log здесь это побочный эффект, но он не повредит. Мы все равно получим те же результаты, учитывая те же данные.
Однако, это может вызвать проблемы.
“Нечистое” изменение объекта
Переменная person была изменена навсегда, потому что функция была объявлена через оператор присваивания.
Разделяемое состояние означает, что влияние impureAssoc уже не полностью очевидно. Понимание влияния на систему теперь включает отслеживание каждой переменной, к которой когда-либо прикасалась, и знание ее истории.
Разделяемое состояние = временные зависимости.
Мы можем очистить impureAssoc, просто вернув новый объект с желаемыми свойствами.
“Очищаем это”
Теперь pureAssoc возвращает тестируемый результат, и можно не беспокоиться, если он изменится где-то в другом месте.
Можно было сделать и так:
Изменять входные данные может быть опасно, но изменять их копию не проблема. Конечный результат — тестируемая, предсказуемая функция, которая работает независимо от того, где и когда вы ее вызываете.
Изменения ограничиваются этой небольшой областью, и вы все еще возвращаете значение.
Резюме
В этой статье вы найдете чек-лист, который поможет определить чистая функция или нет.
Чек-лист
Функция должна удовлетворять двум условиям, чтобы считаться «чистой»:
— Каждый раз функция возвращает одинаковый результат, когда она вызывается с тем же набором аргументов
— Нет побочных эффектов
Рассмотрим подробнее.
1. Одинаковый вход => Одинаковый выход
Сравните это:
const add = (x, y) => x + y;
add(2, 4); // 6
С этим:
let x = 2;
const add = (y) => {
x += y;
};
add(4); // x === 6 (the first time)
В первом случае значение возвращается на основании заданных параметров, независимо от того, где/когда вы его вызываете.
Если вы сложите 2 и 4, всегда получите 6.
Ничего не влияет на результат.
Нечистые функции = непостоянные результаты
Второй пример ничего не возвращает. Он полагается на общее состояние для выполнения своей работы путем увеличения переменной за пределами своей области.
Эта модель кошмар для разработчиков.
Разделяемое состояние вводит зависимость от времени. Вы получаете разные результаты в зависимости от того, когда вы вызвали функцию. В первый раз результат 6, в следующий раз 10 и так далее.
Что лучше?
В каком случае вы получите меньше багов, которые появляются только при определенных условиях?
В каком случае с большей вероятностью вы преуспеете в многопоточной среде, где временные зависимости могут сломать систему?
Определенно в первом.
2. Нет побочных эффектов
Этот тест сам по себе контрольный список.
Примеры побочных эффектов:
- Видоизменение входных параметров
- console.log
- HTTP вызовы (AJAX/fetch)
- Изменение в файловой системе
- Запросы DOM
По сути, любая работа, выполняемая функцией, не связана с вычислением конечного результата.
Советую посмотреть видео Боба Мартина.
Вот “нечистая” функция с побочным эффектом.
const impureDouble = (x) => {
console.log('doubling', x);
return x * 2;
};
const result = impureDouble(4);
console.log({ result });
console.log здесь это побочный эффект, но он не повредит. Мы все равно получим те же результаты, учитывая те же данные.
Однако, это может вызвать проблемы.
“Нечистое” изменение объекта
const impureAssoc = (key, value, object) => {
object[key] = value;
};
const person = {
name: 'Bobo'
};
const result = impureAssoc('shoeSize', 400, person);
console.log({
person,
result
});
Переменная person была изменена навсегда, потому что функция была объявлена через оператор присваивания.
Разделяемое состояние означает, что влияние impureAssoc уже не полностью очевидно. Понимание влияния на систему теперь включает отслеживание каждой переменной, к которой когда-либо прикасалась, и знание ее истории.
Разделяемое состояние = временные зависимости.
Мы можем очистить impureAssoc, просто вернув новый объект с желаемыми свойствами.
“Очищаем это”
const pureAssoc = (key, value, object) => ({
...object,
[key]: value
});
const person = {
name: 'Bobo'
};
const result = pureAssoc('shoeSize', 400, person);
console.log({
person,
result
});
Теперь pureAssoc возвращает тестируемый результат, и можно не беспокоиться, если он изменится где-то в другом месте.
Можно было сделать и так:
const pureAssoc = (key, value, object) => {
const newObject = { ...object };
newObject[key] = value;
return newObject;
};
const person = {
name: 'Bobo'
};
const result = pureAssoc('shoeSize', 400, person);
console.log({
person,
result
});
Изменять входные данные может быть опасно, но изменять их копию не проблема. Конечный результат — тестируемая, предсказуемая функция, которая работает независимо от того, где и когда вы ее вызываете.
Изменения ограничиваются этой небольшой областью, и вы все еще возвращаете значение.
Резюме
- Функция чистая, если не имеет побочных эффектов и каждый раз возвращает одинаковый результат, когда она вызывается с тем же набором аргументов.
- Побочные эффекты включают: меняющийся вход, HTTP-вызовы, запись на диск, вывод на экран.
- Вы можете безопасно клонировать, а затем менять входные параметры. Просто оставьте оригинал без изменений.
- Синтаксис распространения (… syntax) — это самый простой способ клонирования объектов и массивов.