что такое функциональное программирование js

Функциональное программирование с примерами на JavaScript. Часть первая. Основные техники функционального программирования

Авторизуйтесь

Функциональное программирование с примерами на JavaScript. Часть первая. Основные техники функционального программирования

Функциональное программирование, или ФП, может изменить стиль вашего написания программ к лучшему. Но освоить его довольно непросто, а многие посты и туториалы не рассматривают детали (вроде монад, аппликативных функторов и т.п.) и не предоставляют примеры из практики, которые помогли бы новичкам использовать мощные техники ФП ежедневно. Поэтому я решил написать статью, в которой освещу основные идеи ФП.

В первой части вы изучите основы ФП, такие как каррирование, чистые функции, fantasy-land, функторы, монады, Maybe-монады и Either-монады на нескольких примерах.

Функциональное программирование — это стиль написания программ через составление набора функций.

Кроме этого, структура функций должна следовать некоторым правилам, описанным ниже.

Итак, у вас могло возникнуть несколько вопросов. Если любую задачу можно решить, объединяя вызовы нескольких функций, то:

Чтобы решить все эти проблемы, функциональные языки, вроде Haskell, предоставляют инструменты и решения из математики, такие как монады, функторы и т.д., из коробки.

Хотя в JavaScript эти инструменты не встроены, к счастью, у него достаточно преимуществ, позволяющих людям реализовывать недостающие функции в собственных библиотеках.

Спецификация Fantasy-Land и библиотеки ФП

В библиотеках, содержащих такие инструменты, как функторы и монады, реализуются функции и классы, которые следуют некоторым спецификациям, чтобы предоставлять функциональность, подобную стандартной библиотеке Haskell.

Fantasy-Land — одна из таких спецификаций, в которой описано, как должна действовать та или иная функция или класс в JS.

JS-класс — монада, если он реализует функции, требуемые функтором, аппликативным функтором, цепочкой и самой монадой.

Библиотеки, следующие спецификациям Fantasy-Land

Какие же из них мне использовать?

Такие библиотеки, как lodash-fp и ramdajs, позволяют вам начать программировать в функциональном стиле. Но они не реализуют функции, позволяющие использовать ключевые математические концепты (монады, функторы, свертки), а без них невозможно решать некоторые из реальных задач в функциональном стиле.

Так что в дополнение к ним вы должны использовать одну из библиотек, следующих спецификациям FL.

Теперь, когда мы знаем основы, давайте посмотрим на несколько практических примеров и изучим на них некоторые из возможностей и техник функционального программирования.

Пример 1: справляемся с проверкой на NULL

Тема покрывает: функторы, монады, Maybe-монады и каррирование.

Сценарий использования: Мы хотим показать различные стартовые страницы в зависимости от языка, выбранного пользователем в настройках. В данном примере мы реализовываем функцию getUrlForUser, которая возвращает правильный URL из списка indexURLs для испанского языка, выбранного пользователем joeUser.

Проблема: язык может быть не выбран, то есть равняться null. Также сам пользователь может быть не залогинен и равняться null. Выбранный язык может быть не доступен в нашем списке indexURLs. Так что мы должны позаботиться о нескольких случаях, при которых значение null или undefined может вызвать ошибку.

Решение (Императивное против Функционального):

Не беспокойтесь, если функциональное решение пока вам не понятно, я объясню его шаг за шагом немного позже.

Давайте для начала попробуем понять некоторые из концептов ФП, которые были использованы в этом решении.

Функторы

Давайте напишем свой собственный функтор «MyFunctor». Это просто JS-класс (функция-конструктор). Метод map применяет функцию к хранимым значениям и возвращает новый экземпляр MyFunctor.

Монады

Ниже представлена простая реализация монады.

Обычные монады используются нечасто, в отличие от более специфичных монад, таких как «монада Maybe» и «монада Either«.

«Maybe»-монада

Монада «Maybe» — это класс, который имплементирует спецификацию монады. Её особенность заключается в том, что с помощью нее можно решать проблемы с null и undefined.

В частности, в случае, если данные равны null или undefined, функция map пропускает их.

Код, представленный ниже, показывает имплементацию Maybe-монады в библиотеке ramda-fantasy. Она возвращает экземпляр одного из двух подклассов: Just или Nothing, в зависимости от значения.

Обратите особое внимание на функции «map» и «orElse».

Давайте поймем, как Maybe-монада осуществляет проверку на null.

Каррирование

Освещенные темы: чистые функции и композиция.

Но с практической точки зрения многие функции могут принимать несколько параметров. Так как же нам создавать из них цепочки? Ответ: С помощью каррирования.

Каррирование превращает функцию, которая принимает несколько параметров в функцию, которая принимает только один параметр за один раз. Функция не запустится, пока все параметры не будут переданы.

В дополнение, каррирование может быть также использовано в ситуациях, когда мы обращаемся к глобальным значениям.

Давайте снова взглянем на наше решение:

Пример 2: обработка функций, бросающих исключения и выход сразу после ошибки

Освещенные темы: Монада «Either»

Монада Maybe подходит нам, чтобы обработать ошибки, связанные с null и undefined. Но что делать с функциями, которым требуется выбрасывать исключения? И как определить, какая из функций в цепочке вызвала ошибку, когда в серии несколько функций, бросающих исключения?

Например, если func2 из цепочки func1.func2.func3. выбросила исключение, мы должны пропустить вызов func3 и последующие функции и корректно обработать ошибку.

Монада Either

Монада Either превосходно подойдет для подобной ситуации.

Пример использования: В примере ниже мы рассчитываем «tax» и «discont» для «items» и в конечном счете вызываем showTotalPrice.

Заметьте, что функции «tax» и «discount» выбросят исключение, если в качестве цены передано не числовое значение. Функция «discount», помимо этого, вернет ошибку в случае, если цена меньше 10.

Давайте посмотрим, как можно реализовать этот пример в функциональном стиле, используя монаду Either.

Either-монада предоставляет два конструктора: «Either.Left» и «Either.Right«. Думайте о них, как о подклассах Either. И «Left«, и «Right» тоже являются монадами. Идея в том, чтобы хранить ошибки или исключения в Left и полезные значения в Right.

Экземпляры Either.Left или Either.Right создаются в зависимости от значения функции.

Так давайте же посмотрим, как изменить наш императивный пример на функциональный.

Шаг 1: Оберните возвращаемые значения в Left и Right. «Оборачивание» означает создание экземпляра класса с помощью оператора new.

Шаг 2: Оберните исходное значение в Right, так как оно валидно.

Шаг 3: Создайте две функции: одну для обработки ошибок, а другую для отображения результата. Оберните их в Either.either (из библиотеки ramda-fantasy.js).

Either.either принимает 3 параметра: обработчик успешного завершения, обработчик ошибок и монаду Either. Сейчас мы можем передать только обработчики, а третий параметр, Either, передать позже.

Как только Either.either получит все три параметра, она передаст третий параметр в обработчик успешного завершения или обработчик ошибок, в зависимости от типа монады: Left или Right.

Шаг 4: Используйте метод chain, чтобы создать цепочку из нескольких функций, выбрасывающих исключения. Передайте результат их выполнения в Either.either (eitherLogOrShow).

Все вместе выглядит следующим образом:

В следующей части мы рассмотрим аппликативные функторы, curryN и Validation Applicative.

Источник

Основы функционального программирования в JavaScript

Объяснение азов функционального программирования на простых примерах для создания лаконичного и легко поддерживаемого кода.

В последние годы отмечается еще большее разграничение между традиционным и функциональным программированием в JavaScript. Суть его не в превосходстве одного над другим, а в личных предпочтениях.

Данная статья рассчитана на новичков, постигающих азы функционального программирования.

Что такое функциональное программирование в теории?

Конечно же, с функциональным программированием вам придется пересмотреть свое видение кода. Данная концепция активно используется разработчиками в проектах, для которых эффективность и надежность кода стоят на первом месте.

Что такое функциональное программирование на практике?

Взгляните на простой цикл for :

Проще простого, даже гуглить не придется.

Этот пример как нельзя лучше иллюстрирует традиционное использование знаменитого цикла for в качестве итератора.

Чистые функции

Говоря о функциональном программировании, нельзя не упомянуть о чистых функциях. Так что такое чистая функция?

Основное назначение чистой функции – убрать побочные эффекты.

Побочный эффект возникает в функциях, которые возвращают неожиданные результаты, либо оказывают иное влияние на параметры функции, изменяя состояние системы.

При изменении состояния системы возникает угроза целостности программы и снижается качество кода. Одна ошибка ведет к появлению другой. И вот вы уже не понимаете, откуда берутся эти баги. Никому не пожелаешь такого.

Но… чистая функция – это не свойство какого-то одного языка. Ее придумали для обозначения функции, в которой при заданном наборе аргументов всегда возвращаются предсказуемые результаты. Например, 1+2 всегда вернет 3.

Чистота функции часто определяется возвращаемым значением.

Если функция возвращает неожиданное значение даже при одинаковых аргументах, то она называется нечистой функцией (функцией с побочными эффектами).

Можете ли вы писать, в основном, чистые функции? Если так, то вы на шаг ближе к освоению азов функционального программирования.

Сначала чистота функции кажется чем-то малопонятным, особенно без наглядных примеров. Однако компьютерная программа – это нечто большее, чем простой набор операторов. И то, что вы прописываете внутри функций, может затронуть общее состояние программы.

Всегда помните о главном: никто не может писать 100% чистые программы. Но именно чистота функций позволяет избегать многих распространенных ошибок.

Дальше все станет понятнее. Вы увидите, как можно сочетать чистые функции с другими принципами функционального программирования.

Перезапись цикла for для функционального программирования

Для перезаписи цикла for будет использоваться метод массива map (сопоставление).

В EcmaScript 6 с поддержкой парадигмы функционального программирования можно взять стрелочные функции. Стрелочная функция еще больше сокращает функции в коде:

А при удалении return функция принимает следующий вид:

Работает также, но выглядит короче и «функциональнее». В данном случае функциональность не говорит о том, что надо пользоваться только функциями JavaScript. Суть в другом: лаконичный код больше похож на математическое уравнение.

Хотя, может, это «почти что он»?

А метод map приводит к следующему:

Давайте вынесем функцию из метода map и сохраним ее отдельно:

Так функция выглядит немного чище. Тем не менее, значение списка все еще не увеличилось (не инкрементировалось).

Это и есть смена парадигмы. Вам еще предстоит разобраться в причинах, почему результат остается прежним.

Инкрементация списка отсутствует только потому, что map не изменяет сам список. Он возвращает копию списка с применением обратного вызова каждого из элементов. А для получения инкрементации переменной нужно присвоить LIST.map(add) :

Теперь в копии списка хранится инкрементированное значение. Но… это уже не тот массив, с которым вы работали до этого. Опять же – очередной плюс функционального программирования.

Помните, как в начале статьи речь шла о побочных эффектах? Стрелочная функция скрывает собственную область значений, поэтому ей не нужно просачиваться в глобальную область видимости или менять значения начального массива. В рамках функционального программирования – это хорошо. И вполне предсказуемо.

Чистота функции во всей красе! И да, она немного ограничивает возможности разработчика. Но такой код выглядит менее громоздким, а разработчик получает копию начального массива.

Скрытые области функционального программирования

Функциональное программирование – это не просто преобразование цикла for к более лаконичным выражениям. Область применения здесь намного шире. Пример: код выше, в котором функции map и arrow скрывают элементы в своей области действия.

Массив содержит целый набор методов, характерных для функционального программирования.

Один из них называется reduce (сокращение). При соединении map с reduce можно изменять элементы массива без вынесения их в глобальную область видимости. Вся логика программы дальше (отличная практика в разработке).

Кроме того, можно смело удалять return и <> без вреда для функционала:

Опять же, такая структура чем-то похожа на математическое уравнение (функцию), то есть на функциональное программирование. Однако следует четко понимать, что функциональное программирование не есть функции JavaScript. И по мере разрастания первого, второе постепенно сходит на нет.

Аккумулятор всегда присутствует в операции reduce (сокращения). Он отслеживает совокупный эффект операции.

Таким образом, сам цикл начинается с нулевой отметки на счетчике. После выполнения кода аккумулятору присваивается возвращаемое значение (оно хранится в переменной val ).

По мере итерации кода и суммирования функций происходит добавление нового значения.

Функциональное программирование привносит красоту кода и его идеальное выполнение. Функции работают так же четко, как и математическое уравнение.

Источник

Функциональное программирование на Javascript

Возьмем немного функций высшего порядка, добавим частичное применение функций, приправим fold с map-ом и получим Javascript DSL для работы с DOM.

Человеческим языком:
Простое и понятное введение в функциональное программирование на чистом и понятном Javascript.

В отличие от «Через тернии к Haskell» все разжевано (возможно даже слишком) и разложено по полочкам.

Прочтение статьи развоплотит миф о неприменимости ФП в реальной жизни. Вы сможете смотреть на решение одной и той же задачи с разных точек зрения. Прямо как на картинке.

Функции

Начнем с простого определения функции.

Можно тот же код записать по-другому.

Одним из больших плюсов Javascript является то, что функции в нем являются полноценными объектами. Настоящие First Class Citizen.
В отличие, например от Java, где функция отдельно от объекта существовать не может.

Приведенная выше функция работает с побочными эффектами, то есть изменяет состояние внешнего мира. Это выражается в использовании console.log().

А теперь рассмотрим пример чистой функции.

Чистые функции не производят побочных эффектов. Вы передаете в них какие-то данные, и они отдают вам данные обратно. Их очень просто анализировать. Их легче тестировать. Не надо проверять внешние зависимости. Поэтому в большинстве случаев чистые функции предпочтительнее функций с побочным эффектам.
Но, с другой стороны, программа состоящая исключительно из чистых функций не несет практического смысла. Она ничего не считывает и не выводит.
Поэтому логично будет писать программы таким образом, чтобы отделить чистые функции от функций с побочными эффектами и таким образом упростить себе жизнь.

Итак, первое правило функционального программирования — We don’t talk about fight club используем чистые функции.

Функции высшего порядка

Едем дальше. Поскольку функции — это объекты, то мы можем их передавать в другие функции. А функции высшего порядка, это функции, которые возвращают функции, или которые принимают функции в качестве параметра.

Вот простой пример функции, которая тоже возвращает функцию.

И пример ее использования.

А вот достаточно известный пример функции высшего порядка

addEventListener в качестве параметра получает функцию. То есть addEventListener является функцией высшего порядка.

И функция-обработчик будет вызвана, когда произойдет какое-то событие.

Возможно вам более привычен другой вариант:

Или еще тысяча и один способ, которыми jQuery позволяет описывать обработчики.

Итак еще раз определение:
ФВП — это функции, которые либо возвращают функции либо принимают функции в качестве параметров.

Циклы

Старые знакомые.
Под циклом будем понимать стандартное лобовое решение. Примерно такое

Зачем мы используем циклы? Давайте разберем несколько стандартных вариантов использования, и увидим, что циклы — не всегда лучшее решение.

Первый вариант — обход массивов и списков

Обычно такой обход используется совместно с побочными эффектами. И обычно эти эффекты немного полезнее, чем простой вывод в консоль.

Второй вариант — вытаскивание данных из списков

В этом случае — список пользователей твиттера.
При помощи цикла мы получаем список имен наших пользователей

Еще один вариант использования — агрегация данных в списке:

То есть мы агрегируем данные списка, и получаем на выходе другую структуру данных.

foreach

Я говорил, что циклы — не всегда самое лучшее решение, но какие вообще есть альтернативы?

Чем можно заменить подобный цикл?

Вместо пробегать по списку руками, мы можем использовать
метод массива. Передадим туда функцию обрабатывающую каждый элемент и получим необходимый результат.

Но в чем принципиальная разница между этим

К сожалению, синтаксис для описания функций в JS достаточно многословен, поэтому мы не получили значительной экономии в количестве написанного текста.

Но есть еще кое что. Глядя на код, можно сказать, чему уделяется внимание в каждой из реализаций.

Первый участок ориентирован на саму механику цикла. Взять число, увеличить его на единицу, получить элемент массива по индексу, произвести действие.

Второй пример гораздо проще для понимания. Мы делаем что-то с каждым элементом списка.

Во втором примере уровень абстракции гораздо выше. И он позволяет подходить к решению задачи с другой стороны.

Давайте рассмотрим еще одну функцию, которая есть в Javascript.

Это абстракция, которая соответствует трансформации списка.
Используя map мы можем решить эту задачу гораздо проще

Мы избавились от временных переменных, от описания цикла. Прямое и понятный код. И поскольку функция обработки достаточно короткая, мы можем уместить все в одну строку.

Я не фанатик записи кода в одну строку. Но то, сколько идей можно выразить одной строкой говорит о выразительности вашего API.
Теперь поищем упоминания в твиттере.

Достаточно корявый пример. Тут может быть куча ошибок с индексацией и получением элемента массива.
Давайте проанализируем, что мы реально делаем в этом примере:

Перепишем, используя map и join

Возможностей ошибиться стало гораздо меньше.
Но можно ли сделать лучше? :)
Давайте введем еще одну функцию высшего порядка, которую будем использовать для доступа к свойствам объектов.

На первый взгляд она достаточно бессмысленна. Мы передаем в нее имя,
а она возвращает нам функцию, куда передается объект из которого вытаскиваем необходимое поле.

Какое-то запутанное объяснение получилось. Давайте просто попробуем использовать эту фукнцию на реальной задаче.

Итак, еще один однострочник. Достаточно неплохая выразительность. А функция prop не так уж бесполезна.

reduce

Это прабабушка для for, foreach, while и прочих подобных структур. Эта функция также известна под именем fold.

Опять начнем с примитивного примера.

Use the function, Luke.

Сначала мы используем map, чтобы получить список, содержащий длины буферов

А на втором шаге мы применим reduce, чтобы получить их сумму.

Если вы не знакомы с reduce, то она работает очень просто. В нее передается функция-аккумулятор, которая будет применяться к каждому элементу и начальное значение для функции аккумулятора.

Как-то опять слишком сложно. Давайте просто посмотрим, что будет происходить, если мы применим reduce к простому списку.

Итак, с помощью reduce мы можем легко просуммировать элементы списка.

Но у нас уже было что-то похожее. Сравните.

Поэтому мы можем немного упростить нашу функцию по вычислению суммарной длины буферов.

Теперь стало яснее? reduce просто суммирует все элементы списка, применяя функцию add. Начальное значение суммы равно нулю. Что может быть проще?

Но на этом упрощения не заканчиваются. Сравните

В элегантные шорты.

Ну и, естественно, мы можем записать это в одну строку

Использование свертки (reduce) вместо циклов позволяет нам думать на другом уровне абстракции. Мы совершаем операции над списком, а не на уровне каждого элемента.

Асинхронные вызовы

Но использование reduce a.k.a fold для суммирования списков — очень упрощенный пример. Идея гораздо мощнее. Давайте разберем еще один пример.

Одна из проблем использования Javascript в браузере заключается в том, что все выполняется в одном потоке, и поэтому мы должны использовать коллбеки.

Напишем реализацию функции combine. Сначала — лобовой подход.

Для получения скриптов было бы логично использовать jQuery.ajax:

Подобный код не будет тормозить браузер, поскольку запросы к серверу будут отправлены асинхронно. То есть при выполнении будет 3 параллельных запроса.

Напишем обработчик для успешного скачивания скрипта.

Вроде бы функция готова. Но есть два но.
Во-первых уродливо, во-вторых — оно не будет работать.

С чем тут могут быть проблемы? С областями видимости Javascript. В этом языке область видимость не поблочная, а функциональная. то есть все 3 функции будут видеть одно и то значение переменной i. Поскольку цикл отработает раньше, чем придут ответы от сервера, все три функции будут работать с i == 3;
Эта проблема решается стандартным способом — мы кэшируем значение переменной цикла. Но нельзя сказать, что код от этого стал красивее.

Почти даже работает. Для того, чтобы избавиться от замыканий и хитрых переменных, можно использовать foreach

Лучше, конечно, но все равно страшновато. Кстати, код все еще не будет работать правильно. Его можно допилить до работоспособного состояния, но это создаст дополнительные сложности и в разработке и в последующей поддержке.

Continuation Passing Style

Для избавления от головной боли воспользуемся библиотекой

Для работы будем использовать такую вещь как CPS.

Звучит гораздо страшнее, чем есть на самом деле. Это функция, которая получает в качестве параметра другую функцию, и когда первая функция завершается, она вместо retrun вызывает функцию-параметр.

Обернем jQuery.ajax таким образом, чтобы получить требуемый результат.

Функция получает в качестве параметера callback, и мы не описали обработчик ошибок. В реальном коде он обязан быть, но для простоты изложения, мы о нем забудем.
Что же будет, если использовать библиотеку async? Получится что-то типа такого:

Мы имеем готовую функцию map, работающую в асинхронном мире. Кстати, текущая реализация обеспечит правильный порядок склейки скриптов, в отличие от нашего лобового примера.

Сравните с тем, что было:

Поскольку map для меня уже является естественным способом написания программ, я бы никогда не написал кода приведенного выше. Я бы думал, как приспособить map к асинхронному окружению. И если бы не было библиотеки async, то написал бы асинхронный map сам.

Функциональный подход позволяет гораздо проще смотреть на вещи. И реализовывать более красивые решения.

Частичное применение функций

Еще одна идея, которая пришла из функционального программирования, и может быть очень полезной, если уметь ее правильно готовить.

В качестве примера мы будем создавать DOM элементы.
(Прим. переводчика: cull.dom — библиотека, автора, которую он создавал для одного из проектов. Но функции в ней очевидны и просты.)

Также можно задавать атрибуты свойств.

И указывать дочерние элементы

Если их использовать друг внутри друга, можно получить некое подобие DSL для HTML.

А теперь все-таки приступим к обсуждению частичного применения функций. Помните один из первых примеров?

Он возвращает функцию, которая будет суммировать два числа. Естественно, при необходимости мы можем использовать именованные функции.

И теперь мы видим, что функция makeAdder берет функцию add и фиксирует один из ее аргументов. Вы получаете функцию сложения, в которой один из аргументов — константа

Теперь мы получили достаточно интересную возможность — сделать наш DSL по созданию DOM элементов еще красивее.

И можем строить HTML списки приблизительно так

Если вы как и я, не любите программировать на уровне строковых переменных — это отличный способ упростить себе жизнь. У вас теперь будет работать автодополнение кода, и другие приятные вещи. А еще ваш код очень похож на обычный HTML.
И поскольку наш подход достаточно красив, мы можем создать функции для всех элементов документа заранее:

Таким образом, мы создадим функцию для каждого HTML элемента.
Конечно, пространство имен не всегда удобно использовать полностью, поэтому будем упрощать еще дальше.

Теперь мы не завязаны на глобальные переменные и функции, что хорошо.

Композиция функций

Вот еще пример простого приложения — опросника.

Необходимо ответить на каждый блок. Каждый блок содержит несколько вопросов. После ответа на один блок, мы переходим к следующему.

Каждый блок можно представить как панель, которая может быть в режиме вопроса, режиме результата или неактивной.

В каждой панели могут быть разные поля. Строковые, числовые, даты.
Поля могут быть в двух режимах — редактирования или результата.

Посмотрим, как можно подойти к решению этой задачи, используя функциональный подход.

Помните нашу любимую функцию prop?

У нее есть брат-близнец func.

Она возвращает функцию, которую вы можете применять к объектам.

Теперь посчитаем результат каждого блока в опроснике

Принцип должен быть очевиден. Мы возвращаем div, в котором будут элементы, созданные функцией buildSummary для каждого блока опросника.

В этом примере каждый компонент сам знает как представить свой результат. Но иногда панель должна отобразить результат специфическим образом.

Поэтому мы можем написать 2 функции: buildSummary и getSummary.

Первая — строит полное представление, включая html теги.
Вторая — возвращает объект, который содержит необходимые результаты.

И как только нам понадобилась хитрая обработка результатов, вся красота начала рушиться.

Однако, мы уже достаточно функционально ориентированы, чтобы улучить этот кусок кода. Первое очевидное улучшение — применить foreach.

Мы избавились от переменных цикла, но возможно ли использовать map?

Коротко, но далеко до идеала. Основная проблема в этом выражении:

А как насчет нескольких функций map?

Функциональный стиль налицо, но выглядит страшно. И читать очень неудобно.

Но давайте глянем на код еще разок. Что у нас здесь?

Здесь мы вызываем метод объекта. Но ведь мы создали специальную функцию для этого, func.

Мы получаем доступ к свойству объекта. И для этого тоже есть удобная функция.

Остался последний участок.

Мы здесь создаем DOM элемент и устанавливаем его внутреннее свойство. У нас есть что-то похожее в нашем DSL, не правда ли?

Теперь почти красиво. Но есть один нюанс. Мы делаем 3 прохода по списку. В каких-то случаях это может быть нормально, но в целом несколько неоптимально. Что же можно сделать?

Пора использовать композицию функций. Мы хотим заставить одну функцию делать то, что делают три.

Как же нам реализовать compose?

По частям. Для начала создадим синонимы, чтобы не писать много кода.

Все просто и очевидно. Едем дальше. Разберем, что же происходит, когда мы вызываем функцию summarize.

Шаг первый

Объект предеается в последнюю функцию из списка, а именно getSummary. Она возвращает нам объект типа summary. А этот объект передается в следующую функцию, getText

Шаг второй

В результате второго шага мы получим строку, которая содержится в свойстве text. А после этого строка попадет в функцию, которая создаст нам DOM объект p.

Шаг третий

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

Итак, вернемся к нашему многострадальному примеру.

Сначала мы создали функцию вычисления результатов. А потом применили map.
При этом заметьте, что функция summarize абсолютно не знает, с каким объектом она работает. Это три различных абстракции, которые соединяются исключительно благодаря функции compose. Поэтому мы можем вынести summarize в отдельную сущность.

Выглядит здорово и красиво, но что насчет производительности?

Вопросы производительности

for — 5M операций в секунду
forEach — 1,5M операций в секунду
reduce — 1.5M операций в секунду

Работа с DOM — 50K операций в секунду

Так что беспокоиться стоит не о функциональном подходе, а о тормозах работы с DOM. Само собой, тут все зависит от вашей задачи, поэтому если сомневаетесь — делайте замеры. Особенно на мобильных устройствах.

Заключение

Используем чистые функции
Используем функции высшего порядка (map, reduce).
Используем небольшие абстракции.
Много мелких абстракций могут легко собираться в одну большую мощную вещь.

Источник

Понравилась статья? Поделиться с друзьями:

Не пропустите наши новые статьи:

  • что такое фулбоди программа тренировок
  • что такое фронт в программировании
  • Что такое фреймворки в языках программирования
  • что такое фреймворки в программировании
  • что такое фреймворк в программировании простыми словами

  • Операционные системы и программное обеспечение
    0 0 голоса
    Рейтинг статьи
    Подписаться
    Уведомить о
    guest
    0 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии