Чистые функции и побочные эффекты — хорошо известные концепции функционального программирования. Эти концепции также широко используются в JavaScript. Давай учить.
Введение в функции JavaScript
Функция позволяет нам логически размещать код для выполнения задачи. Functions
отлично разбираются в языке программирования JavaScript. Вы можете создавать, изменять функцию, использовать ее в качестве аргумента другой функции или выполнять возврат из функции. Вы также можете присвоить функцию как значение переменной. Короче говоря, вы вряд ли будете использовать или писать какой-либо полезный код JavaScript без использования функций.
В этой статье мы узнаем о Pure Function
, его преимуществах. Мы также рассмотрим Side Effects
и их влияние.
Если вам также нравится учиться на видеоконтенте, эта статья также доступна в виде видеоурока здесь: 🙂
Пожалуйста, не стесняйтесь подписаться на будущий контент
Функция может принимать ноль или более входных данных и производить выходные данные. Вы можете явно вернуть вывод функции, или она просто возвращает undefined
.
Функция, явно возвращающая значение,
// Define the function function testMe(input) { // Returns a string value return `testing ${input}`; } // Invoke the function testMe(123); // returns 'testing 123'
Функция, не возвращающая значение явно,
// Define the function function testMe() { // Do not return anything } // Invoke the function testMe(); // returns undefined
Итак, разобравшись с основными способами использования, давайте рассмотрим сегодняшнюю тему Pure Function
. Мы также поймем концепцию Side Effects
и ее влияние на чистые функции.
Чистые функции и побочные эффекты с примерами
Как программист/разработчик программного обеспечения, вы пишете исходный код для получения вывода на основе входных данных. Обычно вы пишете functions
для выполнения задач на основе входных данных и создания выходных данных. Нам нужно убедиться, что эти функции,
- Предсказуемый: он дает предсказуемый результат для одних и тех же входных данных.
- Читаемый: любой, кто читает функцию как отдельную единицу, может полностью понять ее назначение.
- Многократное использование: можно повторно использовать функцию в нескольких местах исходного кода без изменения ее поведения и поведения вызывающего объекта.
- Тестируемый: мы можем протестировать его как независимую единицу.
Pure Function
обладает всеми вышеперечисленными характеристиками. Это функция, которая производит одинаковый результат для одного и того же входа. Это означает, что он возвращает тот же результат, когда вы передаете одни и те же аргументы. Чистая функция не должна иметь side effects
для изменения ожидаемого вывода.
Приведенная ниже функция sayGreeting()
является чистой функцией. Угадайте, почему?
function sayGreeting(name) { return `Hello ${name}`; }
Это чистая функция, потому что вы всегда получаете Hello <name>
в качестве вывода для прохода <name>
в качестве ввода. Теперь давайте посмотрим на ту же функцию с небольшими изменениями.
let greeting = "Hello"; function sayGreeting(name) { return `${greeting} ${name}`; }
Это чистая функция? Что ж, нет. Вывод функции теперь зависит от внешнего состояния с именем greeting
. Что, если кто-то изменит значение переменной greeting
на Hola
? Это изменит вывод функции sayGreeting()
, даже если вы передадите тот же ввод.
// When greeting is "Hello" sayGreeting('Alex'); // Returns, "Hello Alex" // When greeting is "Hola" sayGreeting('Alex'); // Returns, "Hola Alex"
Итак, здесь мы увидели побочный эффект зависимости от значения внешнего состояния, которое может измениться без ведома функции.
Еще несколько классических случаев побочных эффектов:
- Мутация (изменение) самого ввода.
- Запрос/обновление DOM
- Ведение журнала (даже в консоли)
- Выполнение вызова XHR/fetch.
Любая операция, не связанная напрямую с конечным результатом функции, называется Side Effect
. Теперь давайте посмотрим на функцию impure
, в которой мы изменяем входные данные и делаем то, чего не должны делать в чистой функции.
function findUser(users, item) { const reversedUsers = users.reverse(); const found = reversedUsers.find((user) => { return user === item; }); document.getElementById('user-found').innerText = found; }
Приведенная выше функция принимает два аргумента: набор пользователей (массив) и элемент, который нужно найти в массиве. Он находит элемент с конца массива, переворачивая его. Как только элемент найден в массиве, он устанавливает это значение в виде текста в элемент HTML, используя методы DOM.
Здесь мы нарушаем два основных принципа pure function
.
- Мы мутируем ввод.
- Мы запрашиваем и манипулируем DOM
Итак, какую проблему мы можем предвидеть? Давайте посмотрим. Вызывающий объект вызовет функцию findUser()
следующим образом:
let users = ['Tapas', 'Alex', 'John', 'Maria']; findUser(users, 'Maria');
На этом этапе вызывающая сторона может не знать, что функция выполняет операцию DOM, пока вызывающая сторона не прочитает код функции findUser(). Итак, readability
скомпрометирован. Выход функции выполняет операцию, не связанную с конечным результатом.
Кроме того, мы изменили входной массив. В идеале мы должны были клонировать ввод, а затем мутировать (обратить) копию для операции поиска. Давайте теперь сделаем это чистой функцией.
function findUser(users, item) { // Create the clone of users array and then reverse const reversedUsers = [ ...users].reverse(); // Find the element in the cloned array const found = reversedUsers.find((user) => { return user === item; }); // Return the found element return found; }
Затем,
let users = ['Tapas', 'Alex', 'John', 'Maria']; let found = findUser(users, 'Maria');
Теперь функция findUser()
является чистой функцией. Мы удалили побочные эффекты изменения ввода, и он возвращает предполагаемый результат. Следовательно, функция удобочитаема, тестируема как единое целое, многократно используется и предсказуема.
Чистая функция и побочные эффекты — это концепции functional programming
. Вы можете столкнуться с парой жаргонизмов, которые нуждаются в дружеском пояснении.
- Ссылочная прозрачность: это означает, что мы должны иметь возможность заменить вызов функции (или вызов) ее выходным значением без изменения поведения программы. Как видите, это возможно, только если функция
pure function
.
Возьмем простую чистую функцию,
function multipication(x, y) { return x * y; }
Итак, теперь в этом выражении мы можем заменить вызов функции ее выходным значением с гарантией отсутствия side effect
,
10 + (multiplication(6, 3) ^ 2);
to,
10 + (18 ^ 2);
- Параллельный код. Чистые функции помогают в параллельном выполнении кода. Однако в JavaScript код по умолчанию выполняется последовательно.
Итак, могу ли я сделать все функции Pure Functions
?
Да, технически можно. Но приложение только с чистыми функциями может мало что сделать.
Ваша прикладная программа будет иметь побочные эффекты, такие как вызовы HTTP, запись в консоль, операции ввода-вывода и многое другое. Пожалуйста, используйте чистые функции в максимально возможном количестве мест. Максимально изолируйте нечистые функции (побочные эффекты). Это значительно улучшит читабельность, отладку и тестируемость вашей программы.
Заключение
Использование концепций функционального программирования, таких как чистая функция, с уменьшением побочных эффектов сделает ваш код более удобным для управления и обслуживания. Это означает меньшее количество ошибок, быструю идентификацию проблем, изоляцию проблем, повышенную возможность повторного использования и тестируемость.
Если вы хотите глубже изучить эту тему и углубиться в функциональное программирование, возьмите эту книгу Кайла Симпсона Functional-Light JavaScript. Это стоит прочитать.
Давайте подключимся. Я также делюсь своими знаниями по JavaScript, веб-разработке и ведению блога на этих платформах.
- "Подпишись на меня в Твиттере"
- Подпишитесь на мой канал на YouTube
- Сторонние проекты на GitHub
Первоначально опубликовано на https://blog.greenroots.info.