Programowanie funkcyjne w JavaScript Część 2 - Kombinatory
Paweł Ged
Vue.js Developer
Jest to druga część naszej serii artykułów poświęconych potędze programowania funkcyjnego w JavaScript. Sprawdź ten artykuł, aby poszerzyć swoją wiedzę na temat kombinatorów.
Wprowadzenie do kombinatorów
Kombinatory to funkcje wyższego poziomu, które umożliwiają łączenie funkcji, zmiennych lub innych kombinatorów. Zazwyczaj nie zawierają deklaracji własnych zmiennych lub logiki biznesowej. Są jedynymi, które mogą spłukiwać kontrolę w programie funkcyjnym.
W tym artykule postaram się omówić kilka z nich:
Kran
Currying
Pipe/Compose
Widelec
Alternacja
Sekwencja
Kran
Kombinator jest bardzo przydatny w przypadku funkcji, które nic nie zwracają. Pobiera on funkcję, do której trafia parametr, a następnie jest on zwracany.
const [items, setItems] = useState(() => [])
axios
.get('http://localhost')
.then({ data } => {
setItems(data)
console.log(data)
onLoadData(data)
}).then(...) // zwraca undefined - dane w obietnicy zostały zmodyfikowane
Przykład deklaratywny
const [items, setItems] = useState(() => [])
axios
.get('http://localhost')
.then(({ dane }) => dane)
.then(tap(setItems)) // (dane) => { setItems(dane); return dane }
.then(tap(console.log)) // jeden then = jedna funkcja = jedna odpowiedzialność
.then(tap(onLoadData))
.then(...) // wciąż dostęp do oryginalnych danych
// łatwe w utrzymaniu zasady otwórz/zamknij
Currying
Rozdziela argumenty funkcji i umożliwia ich sekwencyjne wywoływanie.
const sum = (a, b, c) => a + b + c
const currySum = curry(sum)
/*
możliwe wywołania
currySum(a)(b)(c),
currySum(a)(b,c),
currySum(a,b)(c),
currySum(a,b,c)
*/
currySum(1) // (b, c) => 1 + a + b lub (b) => (c) => 1 + a + b
currySum(5)(10) // (c) => 5 + 10 + b
currySum(5, 10) // (c) => 5 + 10 + b
currySum(5)(10)(20) // 35
currySum(5, 10)(20) // 35
currySum(5)(10, 20) // 35
const divideBy = curry((a, b) => b / a)
const multiplyBy = curry((a, b) => a * b)
const divideByTwo = divideBy(2)
divideByTwo(10) // zwraca 5
const multiplyByFive = multiplyBy(5)
multiplyByFive(10) // zwraca 50
Pipe/Compose
Dzięki kompozycji możliwe jest przekazywanie danych z jednej funkcji do drugiej. Ważne jest, aby funkcje przyjmowały taką samą liczbę argumentów. Różnica między pipe i compose polega na tym, że pierwsza z nich wykonuje funkcje od pierwszej do ostatniej, a compose wywołuje je od końca.