Бързо въведение в pipe () и compose () в JavaScript

Функционалното програмиране беше доста открояващо пътуване за мен. Тази публикация и публикации като нея са опит за споделяне на моите виждания и перспективи, докато обикалям нови функционални програми.

Ramda е моята библиотека за FP, тъй като много по-лесно улеснява функционалното програмиране в JavaScript. Горещо го препоръчвам.

Тръба

Концепцията за pipeе проста - съчетава nфункции. Това е тръба, която тече отляво надясно и извиква всяка функция с изхода на последната.

Нека напишем функция, която връща нечия name.

getName = (person) => person.name; getName({ name: 'Buckethead' }); // 'Buckethead' 

Нека напишем функция, която главни низове.

uppercase = (string) => string.toUpperCase(); uppercase('Buckethead'); // 'BUCKETHEAD' 

Така че, ако искахме да получим и използваме personглавното име, можем да направим това:

name = getName({ name: 'Buckethead' }); uppercase(name); // 'BUCKETHEAD' 

Това е добре, но нека премахнем тази междинна променлива name.

uppercase(getName({ name: 'Buckethead' })); 

По-добре, но аз не обичам това гнездене. Може да стане твърде пренаселено. Ами ако искаме да добавим функция, която получава първите 6 знака от низ?

get6Characters = (string) => string.substring(0, 6); get6Characters('Buckethead'); // 'Bucket' 

В резултат на което:

get6Characters(uppercase(getName({ name: 'Buckethead' }))); // 'BUCKET'; 

Нека наистина се побъркаме и добавим функция за обръщане на низове.

reverse = (string) => string .split('') .reverse() .join(''); reverse('Buckethead'); // 'daehtekcuB' 

Сега имаме:

reverse(get6Characters(uppercase(getName({ name: 'Buckethead' })))); // 'TEKCUB' 

Може да получи малко ... много.

Тръба на помощ!

Вместо да заглушаваме функции във функциите или да създаваме куп междинни променливи, нека pipeвсички неща!

pipe( getName, uppercase, get6Characters, reverse )({ name: 'Buckethead' }); // 'TEKCUB' 

Чисто изкуство. Това е като списък със задачи!

Нека да преминем през него.

За демонстрационни цели ще използвам pipeизпълнение от една от статиите за функционално програмиране на Ерик Елиът.

pipe = (...fns) => (x) => fns.reduce((v, f) => f(v), x); 

Обичам тази малка еднолинейка.

Използвайки параметри за почивка , вижте моята статия за това, можем да прехвърлим nфункции. Всяка функция взема изхода на предишната и всичко е намалено ? до единична стойност.

И можете да го използвате точно както го направихме по-горе.

pipe( getName, uppercase, get6Characters, reverse )({ name: 'Buckethead' }); // 'TEKCUB' 

Ще разширя pipeи добавя някои изрази за отстраняване на грешки и ще преминем по ред.

pipe = (...functions) => (value) => { debugger; return functions.reduce((currentValue, currentFunction) => { debugger; return currentFunction(currentValue); }, value); }; 

Обадете се pipeс нашия пример и оставете чудесата да се разкрият.

Вижте локалните променливи. functionsе масив от 4-те функции и valueе { name: 'Buckethead' }.

Тъй като използвахме параметри за почивка , pipeпозволява да се използва произволен брой функции. Той просто ще приключи и ще извика всеки един.

На следващия дебъгер сме вътре reduce. Тук се currentValueпредава currentFunctionи се връща.

Виждаме, че резултатът е, 'Buckethead'защото currentFunctionвръща .nameсвойството на всеки обект. Това ще бъде върнато reduce, което означава, че currentValueследващото ще стане новото . Нека ударим следващия дебъгер и да видим.

Сега currentValueе така, ‘Buckethead’защото това беше върнато миналия път. currentFunctionе uppercase, така 'BUCKETHEAD'ще бъде следващата currentValue.

Същата идея, ‘BUCKETHEAD’извадете първите 6 знака и ги предайте на следващата функция.

reverse(‘.aedi emaS’)

И готово!

Какво ще кажете за compose ()?

Просто е pipeв другата посока.

Така че, ако искате същия резултат като нашия pipeпо-горе, бихте направили обратното.

compose( reverse, get6Characters, uppercase, getName )({ name: 'Buckethead' }); 

Забележете как getNameе последен във веригата и reverseпърви?

Ето бързо изпълнение на compose, отново с любезното съдействие на Магическия Ерик Елиът, от същата статия.

compose = (...fns) => (x) => fns.reduceRight((v, f) => f(v), x); 

Ще оставя разширяването на тази функция с debuggers като упражнение за вас. Поиграйте с него, използвайте го, оценете го. И най-важното, забавлявайте се!