Фото від Joan Gamell на Unsplash
Функціональне програмування стає все популярнішим у JavaScript, особливо з ростом попиту на чистіший, зрозуміліший і легший для підтримки код. В основі цього стилю програмування лежить принцип з’єднання функцій для перетворення даних крок за кроком, процес, який традиційно базувався на вкладених викликах функцій або ланцюжках методів. І ось з’являється оператор конвеєра JavaScript (|>
) — пропозиція, яка покликана зробити функціональне програмування в JavaScript більш інтуїтивним і зручним для читання.
Ця стаття розгляне, що таке оператор конвеєра, його переваги, як він вписується в функціональне програмування і надасть практичні приклади його використання.
Що таке оператор конвеєра?
Оператор конвеєра — це новий синтаксичний елемент JavaScript (на даний момент знаходиться на етапі 2 в процесі пропозиції TC39), що позначається символом |>
.
Цей оператор дозволяє передавати результат однієї функції безпосередньо в іншу, усуваючи потребу у глибоко вкладених функціях. Натхненний оператором конвеєра командного рядка Unix (|
), який передає результат однієї команди наступній, оператор конвеєра має на меті забезпечити подібний потік для функцій JavaScript.
Основний синтаксис
З оператором конвеєра ви можете переписати вирази, для яких зазвичай використовують ланцюжки або вкладені функції, у просту послідовність зліва направо:
value |> functionA |> functionB |> functionC
Тут value
передається у functionA
, результат functionA
передається в functionB
і так далі, поки фінальний результат не буде виведений за допомогою functionC
.
Чому оператор конвеєра важливий
Оператор конвеєра пропонує кілька переваг, особливо для розробників, які використовують функціональне програмування в JavaScript:
- Покращена читаність: Завдяки усуненню вкладених викликів, код спрощується, що робить складні трансформації легшими для розуміння.
2. - Покращена композиційність: Функції можуть бути складені в більш лінійній, зручній для людини послідовності, що відповідає тому, як ми уявляємо трансформації даних.
- Зменшене когнітивне навантаження: Завдяки оператору конвеєра, розробникам не потрібно "розгорнути" вкладені функції в голові, що робить код легшим для розуміння.
5. - Відповідність функціональному програмуванню: Оператор конвеєра природно підходить для патернів функціонального програмування, дозволяючи передавати дані через чисті функції більш інтуїтивно.
Використання оператора конвеєра: до і після
Давайте розглянемо кілька прикладів, щоб зрозуміти, як оператор конвеєра покращує читаність коду та спрощує його.
Приклад 1: Без оператора конвеєра
Розглянемо наступний приклад, де ми хочемо взяти рядок, перетворити його на малі літери, видалити пробіли та потім зробити першу літеру великою:
const capitalizeFirstLetter = (str) =>
str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
const processString = (str) =>
capitalizeFirstLetter(str.trim().toLowerCase());
console.log(processString(" Hello World "));
Хоча цей код читабельний, з ростом кількості функцій вкладені виклики можуть стати складними для управління та розуміння.
Приклад 2: З оператором конвеєра
Використовуючи оператор конвеєра, ми можемо виразити ту саму функціональність з більш природнім потоком:
const result = " Hello World "
|> (str) => str.trim()
|> (str) => str.toLowerCase()
|> capitalizeFirstLetter;
console.log(result);
Код став більш читабельним, рухаючись зліва направо, що дозволяє вам відслідковувати кроки трансформації даних з мінімальними зусиллями.
Кожен крок стає незалежною, модульною трансформацією, яку легко зрозуміти окремо.
Просунуте використання оператора конвеєра з функціями та бібліотеками
Оператор конвеєра особливо потужний, коли його комбінувати з бібліотеками, що підтримують функціональне програмування, такими як lodash або Ramda.
Давайте розглянемо, як оператор конвеєра може спростити такий код.
Приклад 2: Обробка даних за допомогою Lodash
Розглянемо обробку списку чисел, де нам потрібно відфільтрувати непарні числа, піднести кожне число до квадрата та знайти суму:
Без оператора конвеєра
import _ from "lodash";
const result = _.sum(
_.map(
_.filter([1, 2, 3, 4, 5], (n) => n % 2 === 0),
(n) => n * n
)
);
console.log(result);
Цей вкладений підхід працює, але він занадто багатослівний і швидко стає важким для розуміння у складних конвеєрах.
З оператором конвеєра
import _ from "lodash";
const result = [1, 2, 3, 4, 5]
|> (_data) => _.filter(_data, (n) => n % 2 === 0)
|> (_data) => _.map(_data, (n) => n * n)
|> (_data) => _.sum(_data);
console.log(result);
Тут кожен крок трансформації чіткий, що дозволяє читачу легко відслідковувати потік даних на кожному етапі без заглиблення у вкладені структури.
Обробка більш складних трансформацій з оператором конвеєра
Припустимо, ви працюєте з даними користувачів і потрібно отримати користувачів з API, відфільтрувати їх за віком, відсортувати за ім'ям та витягти тільки їхні імена.
Без оператора конвеєра
fetch("https://api.example.com/users")
.then((response) => response.json())
.then((data) => data.filter((user) => user.age >= 18))
.then((filteredUsers) => filteredUsers.sort((a, b) => a.name.localeCompare(b.name)))
.then((sortedUsers) => sortedUsers.map((user) => user.name))
.then((names) => console.log(names));
З оператором конвеєра
const fetchUsers = () => fetch("https://api.example.com/users").then(res => res.json());
fetchUsers()
|> (data) => data.filter((user) => user.age >= 18)
|> (filteredUsers) => filteredUsers.sort((a, b) => a.name.localeCompare(b.name))
|> (sortedUsers) => sortedUsers.map((user) => user.name)
|> (names) => console.log(names);
Цей підхід на основі конвеєра є простим, дозволяючи зосередитися на кроках трансформації, не стикаючись з глибоко вкладеним кодом.
Кожна функція є модульною і може бути змінена незалежно, що ще більше сприяє дотриманню принципів чистого коду.
Додаткові можливості оператора конвеєра
Оператор конвеєра в JavaScript має потенціал для підтримки додаткових синтаксичних можливостей, що розширюють гнучкість.
Два помітних підходи, що розглядаються, це чисті конвеєри та конвеєри в стилі теми.
Чисті конвеєри
Чисті конвеєри дозволяють передавати кожне значення як окремий аргумент без обгортання його в стрілкову функцію:
" Hello World "
|> String.prototype.trim
|> String.prototype.toLowerCase
|> capitalizeFirstLetter;
Цей синтаксис дозволяє безпосередньо викликати існуючі методи прототипу, зменшуючи кількість шаблонного коду та покращуючи читабельність для простих перетворень.
Конвеєри в стилі теми
У конвеєрах в стилі теми, заповнювач, як-от #
, представляє значення вводу на кожному етапі, що дає додаткову гнучкість для більш складних перетворень:
" Hello World "
|> (str) => str.trim()
|> (str) => str.toLowerCase()
|> (str) => str.charAt(0).toUpperCase() + str.slice(1);
Прийняття функціонального програмування з оператором конвеєра
Оператор конвеєра особливо підходить для функціональних патернів програмування (functional programming patterns), які акцентують увагу на незмінності (immutability), трансформації даних та чистих функціях (pure functions).
У функціональному програмуванні дані проходять через серію трансформацій, і оператор конвеєра надає природний синтаксис для підтримки цього процесу.
Функціональні бібліотеки та парадигми часто пропагують код, що є модульним, тестованим та повторно використовуваним — якості, які покращуються завдяки читабельності та композиційності, яку надає оператор конвеєра. Комбінування оператора конвеєра з такими бібліотеками, як RxJS, Lodash або Ramda, які є за своєю суттю функціональними, дозволяє розробникам JavaScript використовувати ці патерни більш інтуїтивно.
Висновок
Оператор конвеєра представляє собою значущий крок у бік того, щоб зробити JavaScript більш сумісним з парадигмами функціонального програмування. Дозволяючи функціям поєднуватися у чіткий, ліво-направо потік, оператор може зробити складні трансформації даних більш доступними, читабельними та підтримуваними.
Хоча це все ще пропозиція, її потенціал для покращення якості коду та читабельності очевидний, і розробники JavaScript з нетерпінням слідкують за її розвитком.
Готуючись до того, щоб оператор конвеєра став частиною стандарту JavaScript, подумайте, як функціональні патерни програмування можуть принести користь вашій кодовій базі, зробивши її більш модульною та адаптивною. Приймаючи оператор конвеєра, ви будете готові повною мірою скористатися еволюцією можливостей JavaScript для більш чистого, читабельного та підтримуваного коду.
Перекладено з: The JavaScript Pipeline Operator: Revolutionizing Functional Programming