Vue v3 был обновлен, чтобы включить новый Composition API, который, как и обновление хуков React пару лет назад, полностью охватывает шаблоны функционального программирования.
И хуки, и Composition API являются отражением того факта, что функциональное программирование штурмом захватило мир разработчиков за последние несколько лет.
Около двух лет назад я начал более серьезно изучать функциональные концепции, потому что хотел наконец понять, что такое монада. Я до сих пор не до конца их понимаю, но я хорошо разобрался в функциональных принципах.
Каковы основные принципы работы?
Многие разработчики уже знают об этом, поэтому кратко обрисую их в общих чертах:
- Функции должны иметь возможность заменять буквальное значение.
- Они должны принимать только один аргумент.
- Они не должны изменять свои ценности.
- Они не должны полагаться или вызывать побочные эффекты (например, использование других функций из глобальной области видимости или добавление к
window
).
Я обнаружил, что приближение к этим принципам может сделать мой код очень чистым, а также очень оптимизированным, но я также обнаружил, что, когда я захожу слишком далеко, мой код может стать претенциозным, например написано нечитабельно.
Переломный момент
Несколько лет назад я получил действительно хороший совет от разработчика, который сказал: «Сначала напишите глупый код, а затем постепенно делайте его умнее».
Давайте взглянем на скрипт, который я написал, чтобы сделать несколько кнопок социальных сетей на каждом этапе. От глупого к лаконичному, а затем к претенциозному. Я хочу попытаться определить, где переломный момент.
Фаза 1
Хорошо, это самая тупая версия кода, она идет шаг за шагом. Сначала я беру элемент, значок твиттера, по его идентификатору. Затем я добавляю прослушиватель событий щелчка, который открывает новое окно со ссылкой на Twitter, encodeURI
просто проверяет правильность форматирования пробелов и специальных символов.
Это отлично работает, но его нельзя использовать повторно, и он работает только для Twitter.
Фаза 2
Давайте завернем его в функцию, создадим аргументы id
и url
и вызовем функцию, передав специфические для Twitter части, а не запрограммировав их жестко.
Теперь это шаг к тому, чтобы быть функциональным — ну, по крайней мере, это функция! — но есть пара проблем. Во-первых, мне не нравится, что window.location.href
используется внутри функции, это означает, что мы можем использовать эту функцию только для href текущего окна.
Другая проблема заключается в том, что здесь нет обработки ошибок, el
может оцениваться как undefined
, что сломает все, когда я попытаюсь получить доступ к el.onclick
.
Фаза 3
Чтобы решить проблему onclick
, мы будем использовать вместо этого addEventListener
, таким образом, мы можем просто использовать ?.
для доступа к нему, не опасаясь выдать какие-либо ошибки.
Еще я переместил window.location.href
в верхнюю область видимости, так что теперь функция не так сильно мутирует url
.
Это лучше, теперь эта функция даже не предназначена специально для обмена в социальных сетях, это просто помощник для добавления любого URL-адреса к событию клика любого элемента.
Но это все еще не функциональная функция. Он принимает более одного аргумента, использует document.getElementById
, window.open
и encodeURI
, которые являются побочными эффектами, технически мутирует url
с encodeURI
и ничего не возвращает!
Фаза 4
Если мы собираемся сделать addUrlToOnclick
правильно функционирующим, он не может полагаться на document.getElementById
, мы должны сначала получить элемент, а затем передать его в качестве аргумента:
Затем мы хотим вернуть значение, чтобы это был элемент с добавленным к нему событием клика:
[Считается ли element.addEventListener
мутацией? Донно, неважно.]
Кроме того, window
и encodeURI
также необходимо использовать вне функции, поэтому мы просто используем функцию обратного вызова в качестве второго аргумента.
Мы больше не можем называть это addUrlToOnclick
, потому что мы удалили эту функцию. Назовем его addEventToElement
.
Также у нас все еще слишком много аргументов, функциональное программирование допускает только один. Пусть addUrlToOnclick
возвращает другую функцию, которая принимает второй аргумент:
Вот как это будет называться:
Теперь это выглядит довольно хорошо, его можно использовать повторно — хотя и немного многословно — и это также довольно явно. Но мы по-прежнему полагаемся на замыкания, чтобы добавить наш обратный вызов, не создавая дополнительных функций, поэтому мы можем пойти дальше.
Пойдем дальше.
Фаза 5
Что мы хотим сделать, так это передать простую функцию в качестве нашего обратного вызова, поэтому давайте сначала создадим эту функцию:
Но это сломается, потому что windowOpen
вызывается, как только вы передаете его в аргументе, поэтому давайте вернем третью функцию:
Теперь это становится запутанным, поэтому я бы также сделал некоторые аргументы переменными, чтобы дать им более понятные имена, а затем передать их в функцию:
Теперь код — как и в начале — не очень пригоден для повторного использования, поэтому давайте просто используем encodeURI
непосредственно внутри windowOpen
…
…и превратить elementById
в функцию…
Теперь все является функцией:
Теперь, я не знаю о вас, но я думаю, что это зашло немного далеко. Если бы я хотел повторно использовать addEventToElement
, мне пришлось бы также перетаскивать еще две функции.
В общем, я только что переписал addEventListener
. Я был вынужден сделать свою функцию слишком низкоуровневой, чтобы выполнять ту работу, которую я хотел.
Кроме того, это выглядит очень запутанным… для меня. Я не думаю, что очень понятно, что происходит.
Какую фазу мне следует остановить?
Думаю, многие скажут, что в конце этапа 5…
Здесь код больше всего похож на хук React. Понятно, что происходит, реализация довольно прозрачна и функциональна, но не претенциозна.
Но на самом деле я остановился на Фазе 4…
Это была наиболее повторно используемая и полнофункциональная фаза сценария.
Мне пришлось использовать эту функцию для трех отдельных элементов, и хотя версия Phase 5 была наиболее прозрачной, эта сделала то, что мне было нужно, и заняла гораздо меньше места.
Но это совсем не функционально.
Является ли функциональное программирование претенциозным?
Это совсем не то, что я говорю здесь. Мне очень нравится функциональное программирование, оно заставляет меня думать о программировании в новом свете и позволяет использовать некоторые действительно интересные шаблоны.
Функциональное программирование — это круто, и оно отзывчиво, и его изучение сделает вас лучше и программирование, но не нужно пугаться кодовых парней. Гораздо важнее быть ясным, чем умным.