Функционалното програмиране беше доста открояващо пътуване за мен. Тази публикация и публикации като нея са опит за споделяне на моите виждания и перспективи, докато обикалям нови функционални програми.
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);
Ще оставя разширяването на тази функция с debugger
s като упражнение за вас. Поиграйте с него, използвайте го, оценете го. И най-важното, забавлявайте се!