Εισαγωγή στους Συνδυαστές
Οι συνδυαστές είναι λειτουργίες υψηλότερου επιπέδου που σας επιτρέπουν να συνδυάζετε συναρτήσεις, μεταβλητές ή άλλους συνδυαστές. Συνήθως, δεν περιέχουν δηλώσεις δικών τους μεταβλητών ή επιχειρηματικής λογικής. Είναι οι μόνοι που ξεπλένουν τον έλεγχο σε ένα πρόγραμμα συναρτήσεων.
Σε αυτό το άρθρο, θα προσπαθήσω να καλύψω μερικά από αυτά:
- Πατήστε το
- Currying
- Σωλήνας/σύνθεση
- Πιρούνι
- Εναλλαγή
- Ακολουθία
Πατήστε το
Ένας συνδυαστής είναι πολύ χρήσιμος για συναρτήσεις που δεν επιστρέφουν τίποτα. Παίρνει τη συνάρτηση στην οποία πηγαίνει η παράμετρος και στη συνέχεια επιστρέφεται.
Δήλωση
const tap = (fn) => (value) => {
fn(value),
return value,
};
Επιτακτικό παράδειγμα
const [items, setItems] = useState(() => [])
axios
.get('http://localhost')
.then({ data } => {
setItems(data)
console.log(data)
onLoadData(data)
}).then(....) // επιστρέφει undefined - τα δεδομένα στην υπόσχεση έχουν τροποποιηθεί
Δηλωτικό παράδειγμα
const [items, setItems] = useState(() => [])
axios
.get('http://localhost')
.then(({ data }) => data)
.then(tap(setItems)) // (data) => { setItems(data); return data }
.then(tap(console.log)) // one then = one function = one responsibility
.then(tap(onLoadData))
.then(....) // εξακολουθεί να έχει πρόσβαση στα αρχικά δεδομένα
// εύκολο στη διατήρηση της αρχής του ανοίγματος/κλεισίματος
Currying
Διαχωρίζει τα ορίσματα μιας συνάρτησης και καθιστά δυνατή τη διαδοχική κλήση τους.
Δήλωση
const curry = (fn) => {
const curried = (...args) => {
if (fn.length !== args.length){
return curried.bind(null, ...args)
}
return fn(...args),
};
return curried
};
Παράδειγμα
const curry = (fn) => {
const curried = (...args) => {
if (fn.length !== args.length){
return curried.bind(null, ...args)
}
return fn(...args),
};
return curried
};
const sum = (a, b, c) => a + b + c
const currySum = curry(sum)
/*
Πιθανές κλήσεις
currySum(a)(b)(c),
currySum(a)(b,c),
currySum(a,b)(c),
currySum(a,b,c)
*/
currySum(1) // (b, c) => 1 + a + b ή (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) // επιστρέφει 5
const multiplyByFive = multiplyBy(5)
multiplyByFive(10) // επιστρέφει 50
Σωλήνας/σύνθεση
Μέσω της σύνθεσης, είναι δυνατή η μεταφορά δεδομένων από μια συνάρτηση σε μια άλλη. Είναι σημαντικό οι συναρτήσεις να λαμβάνουν τον ίδιο αριθμό ορίων. Η διαφορά μεταξύ pipe και compose είναι ότι η πρώτη εκτελεί τη συνάρτηση από την πρώτη έως την τελευταία, ενώ η compose τις καλεί από το τέλος.
Δήλωση
const pipe = (...fns) => (value, ...args) =>
fns.reduce((v, f, i) =>
i === 0
? f(v, ...args)
: f(v),
value),
const compose = (...fns) => (value, ...args) =>
fns.reduceRight((v, f, i) =>
i === (fns.length - 1)
? f(v, ...args)
: f(v),
value),
const pipe = (...fns) => (value, ...args) =>
fns.reduce((v, f, i) =>
i === 0
? f(v, ...args)
: f(v),
value),
const compose = (...fns) => (value, ...args) =>
fns.reduceRight((v, f, i) =>
i === (fns.length - 1)
? f(v, ...args)
: f(v),
value),
Επιτακτικό παράδειγμα
const sine = (val) => Math.sin(val * Math.PI / 180) // not readable
sine(90) // επιστρέφει 1
Δηλωτικό παράδειγμα
const sine = pipe(
multiplyBy(Math.PI) // ↓ val * Math.PI
divideBy(180), // ↓ val * Math.PI / 180
Math.sin, // ↓ Math.sin(val * Math.PI / 180)
)
const sine = compose(
Math.sin, // ↑ Math.sin(val * Math.PI / 180)
divideBy(180), // ↑ val * Math.PI / 180
multiplyBy(Math.PI) // ↑ val * Math.PI
)
sine(90) // επιστρέφει 1
Πιρούνι
Ο συνδυαστής διακλάδωσης είναι χρήσιμος σε περιπτώσεις όπου θέλετε να επεξεργαστείτε μια τιμή με δύο τρόπους και να συνδυάσετε το αποτέλεσμα.
Δήλωση
const fork = (join, fn1, fn2) => (value) => join(fn1(value), fn2(value)),
Παράδειγμα
const length = (array) => array.length
const sum = (array) => array.reduce((a, b) => a + b, 0)
const divide = (a, b) => a / b
const arithmeticAverage = fork(divide, sum, length)
arithmeticAverage([5, 3, 2, 8, 4, 2]) // επιστρέφει 4
Εναλλαγή
Αυτός ο συνδυαστής δέχεται δύο συναρτήσεις και επιστρέφει το αποτέλεσμα της πρώτης αν είναι αληθές. Διαφορετικά, επιστρέφει το αποτέλεσμα της δεύτερης συνάρτησης.
Δήλωση
const alt = (fn, orFn) => (value) => fn(value) || orFn(value)
Παράδειγμα
const users = [{
uuid: '123e4567-e89b-12d3-a456-426655440000',
name: 'William'
}]
const findUser = ({ uuid: searchesUuid }) =>
users.find(({ uuid }) => uuid === searchesUuid)
const newUser = data => ({ ...data, uuid: uuid() // δημιουργία νέου uuid })
const findOrCreate = alt(findUser, newUser)
findOrCreate({ uuid: '123e4567-e89b-12d3-a456-426655440000' }) // επιστρέφει το αντικείμενο William
findOrCreate({ name: 'John' }) // επιστρέφει το αντικείμενο John με νέο uuid
Ακολουθία
Δέχεται πολλές ανεξάρτητες συναρτήσεις και μεταβιβάζει την ίδια παράμετρο σε καθεμία από αυτές. Συνήθως, οι συναρτήσεις αυτές δεν επιστρέφουν καμία τιμή.
Δήλωση
const seq = (...fns) => (val) => fns.forEach(fn => fn(val))
Παράδειγμα
const appendUser = (id) => ({ name }) => {
document.getElementById(id).innerHTML = name
}
const printUserContact = pipe(
findOrCreate, // επιστρέφει τον χρήστη
seq(
appendUser('#contact'), // user => void
console.log, // user => void
onContactUpdate // user => void
)
)
printUserContact(userData)
