Практическое руководство по написанию более функционального JavaScript

Практическое руководство по написанию более функционального JavaScript

От автора: функциональное программирование великолепно. С появлением React все больше и больше внешнего кода JavaScript пишется с учетом принципов ФП. Но как нам начать использовать образ мышления ВП в повседневном кодировании? Рассмотрим подробно, как пишется функциональный JavaScript. Я попытаюсь использовать обычный блок кода и шаг за шагом пояснить его рефакторинг.

Проблема: Пользователь, который заходит на нашу страницу /login, может иметь параметр запроса redirect_to. Например, /login?redirect_to=%2Fmy-page. Обратите внимание, что %2Fmy-page — это на самом деле /my-page, когда она закодирована как часть URL. Нам нужно извлечь эту строку запроса и сохранить ее в локальном хранилище, чтобы после входа в систему пользователь мог быть перенаправлен к my-page.

Шаг № 0: Императивный подход

Если бы нам пришлось выразить решение в простейшей форме списка команд, как бы мы его написали? Нам нужно будет:

Разобрать строку запроса.

Получить значение redirect_to.

Декодировать это значение.

Сохранить декодированное значение в localStorage.

И нам также нужно добавить блоки try catch вокруг «небезопасных» функций. При этом наш блок кода будет выглядеть так:

Шаг № 1: Запись каждого шага как функции

На мгновение давайте забудем о блоках try catch и попробуем выразить все, как функцию.

Когда мы начинаем выражать все наши «результаты» как результаты функций, мы видим, что мы можем выйти из нашего основного тела функции. Когда это происходит, наша функция становится намного проще, а тестирование — намного легче осуществлять.

Ранее мы бы тестировали основную функцию в целом. Но теперь у нас есть 4 функции меньшего размера, и некоторые из них просто передают другие функции, поэтому диапазон, который необходимо протестировать, значительно меньше.
Давайте выявим эти прокси-функции и удалим прокси, чтобы у нас было немного меньше кода.

Шаг № 2: Составление функций

Хорошо. Теперь кажется, что функция persistRedirectToParams представляет собой «композицию» из 4 других функций. Давайте посмотрим, сможем ли мы написать эту функцию как композицию, тем самым исключив промежуточные результаты, которые мы храним как consts.

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

Шаг № 3: Более читаемая композиция

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

Особенность compose состоит в том, что она сокращает функции справа налево. Таким образом, первая функция, которая вызывается в цепочке compose, это последняя функция.

Это не проблема, если вы математик и знакомы с концепцией, вы, естественно, будете читать это справа налево. Но остальные из нас хотели бы прочитать это слева направо.

Шаг № 4: Пайпинг и уплощение

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

Кроме того, кажется, наша функция persistRedirectToParams стала оболочкой для другой функции, которую мы вызываем — op. Другими словами, все, что она делает, это выполняет op. Мы можем избавиться от оболочки и «сгладить» нашу функцию.

Все почти готово. Помните, что мы оставили блок try-catch? Ну, нам нужен какой-то способ представить его обратно. qs.parse небезопасно, как и storeRedirectToQuery. Один из вариантов — сделать их функциями-оболочками и поместить их в блоки try-catch. Другой, функциональный способ — выразить try-catch, как функцию.

Шаг № 5: Обработка исключений в виде функции

Есть некоторые утилиты, которые делают это, но давайте попробуем написать что-нибудь сами.

Наша функция ожидает объект opts, который будет содержать функции tryer и catcher. Он вернет функцию, которая при вызове с аргументами вызывает tryer с указанными аргументами, а при ошибке вызывает catcher. Теперь, если у нас есть небезопасные операции, мы можем поместить их в раздел tryer и, если они не проходят, выдать безопасный результат из раздела catcher (и даже зарегистрировать ошибку).

Шаг № 6: Собираем все вместе

Итак, наш окончательный код выглядит так:

Это более или менее то, что нам нужно. Но чтобы улучшить читаемость и тестируемость кода, мы можем выделить и «безопасные» функции.

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

Есть еще синтаксический сахар ФП, который делает все еще лучше, но это на другой раз.

Автор: Nadeesha Cabral

Источник: //medium.freecodecamp.org/

Редакция: Команда webformyself.

Метки:

Похожие статьи:

Комментарии Вконтакте: