Функциональное программирование: что такое Compose и Pipe в JavaScript?
Compose
и Pipe
- одни из самых мощных концепций функционального программирования на JavaScript. Однако их бывает сложно понять. Эта статья поможет вам лучше понять эти функции.
Написать
В алгебре композиция функций позволяет применять одну функцию к выходным данным другой функции.
В этом примере функция g
применяется к результату применения функции f
к x
. Как видим, композиция функций работает справа налево.
Тот же результат может быть достигнут в JavaScript с помощью compose
:
ОК… действительно сбивает с толку. Давайте посмотрим на пример.
Предположим, мы хотим получить имя пользователя в верхнем регистре. Прежде всего, мы должны написать функцию, которая извлекает имя пользователя:
const user = {name: 'Gianmarco', password: 1234} const getUserName = (user) => user.name getUserName(user) // 'Gianmarco'
А затем функция, которая переводит строки в верхний регистр:
const upperCase = (string) => string.toUpperCase() upperCase('Gianmarco') // 'GIANMARCO'
Теперь мы можем скомпоновать две функции так, чтобы одна функция выполняла оба действия: получить имя и прописные буквы.
Мы можем использовать реализацию compose()
, которую мы видели раньше:
Проблема с этой реализацией compose()
заключается в том, что она принимает в качестве параметров только две функции (в нашем примере upperCase()
и getUserName()
).
Предположим, мы хотим добавить еще одну функцию, которая возвращает первые четыре символа строки:
const firstFour = (string) => string.substring(0,4) firstFour(‘GIANMARCO’); // 'GIAN'
Как мы можем составлять более двух функций одновременно?
Мы можем использовать Compose
и метод reduceRight()
:
const compose = (...functions) => x => functions.reduceRight((acc, fn) => fn(acc), x);
В этой реализации compose()
принимает параметры отдыха (любое количество параметров - в этом примере любое количество функций) и возвращает функцию, которая принимает начальное значение x
. Затем он использует метод reduceRight()
для итерации справа налево по каждой функции fn
в functions
и, в свою очередь, применяет его к накопленному значению acc
.
Проще говоря, compose()
применяет справа налево любое количество функций к выходу предыдущей функции.
С помощью этой новой реализации compose()
мы теперь можем создать функцию, которая получает имя пользователя, вводит его в верхний регистр и возвращает только первые четыре символа:
Круто, правда?
Это похоже на список команд, которые работают справа налево (как в математическом смысле). Функция getUserName()
- это последний аргумент, когда мы вызываем compose()
, потому что это первая функция, которая должна быть выполнена.
Труба
Pipe
в точности похож на compose()
, но работает слева направо. Я лично предпочитаю его 25, потому что вы можете думать об этом как о последовательности событий.
Если мы хотим воссоздать нашу compose()
функцию выше, но с pipe()
, мы можем использовать эту реализацию:
const pipe = (...functions) => x => functions.reduce((acc, fn) => fn(acc), x);
Как вы заметили, теперь мы используем reduce()
вместо reduceRight()
, поскольку функция выполняет итерацию слева направо.
Наш окончательный результат будет:
Как последовательность событий, pipe()
применяет getUserName()
к нашим исходным данным, затем применяет upperCase()
к результату применения getUserName()
к нашим исходным данным. Наконец, он применитfirstFour()
к результату применения upperCase()
к результату применения getUserName()
к нашим исходным данным.
Заключение
Надеюсь, эта статья прояснила некоторые из ваших сомнений и помогла вам понять потенциал Compose
и Pipe
.
Теперь вы можете создавать функции, работающие как фабричные конвейерные ленты, которые получают данные, и эти данные проходят через все эти различные функции, пока мы, наконец, не получим наш результат.