En hurtig introduktion til pipe () og komponere () i JavaScript

Funktionel programmering har været en ganske åben åbning for mig. Dette indlæg og indlæg som det er et forsøg på at dele min indsigt og perspektiver, når jeg trækker nye funktionelle programmeringslande.

Ramda har været mit gå til FP-bibliotek på grund af hvor meget lettere det gør funktionel programmering i JavaScript. Jeg kan varmt anbefale det.

Komponering af blokke til dannelse af en struktur. Smukke dybe ting ...

Rør

Konceptet med rør er enkelt - det kombinerer n-funktioner. Det er et rør, der flyder fra venstre til højre, der kalder hver funktion med output fra den sidste.

Lad os skrive en funktion, der returnerer en persons navn.

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

Lad os skrive en funktion, der har store bogstaver.

store bogstaver = (streng) => string.toUpperCase ()
store bogstaver ( 'Buckethead')
// 'BUCKETHEAD'

Så hvis vi ønskede at få og aktivere personens navn, kunne vi gøre dette:

name = getName ({name: 'Buckethead'})
store bogstaver (navn)
// 'BUCKETHEAD'

Det er fint, men lad os fjerne det mellemliggende variabelnavn.

store bogstaver (getName ({navn: 'Buckethead'}))

Bedre, men jeg er ikke glad for det rede. Det kan blive for overfyldt. Hvad hvis vi vil tilføje en funktion, der får de første 6 tegn i en streng?

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

Resulterende i:

get6Characters (store bogstaver (getName ({navn: 'Buckethead'})))
'SPAND'

Lad os blive skøre og tilføje en funktion til at vende strenge.

reverse = (string) => string
  .dele('')
  .baglæns()
  .tilslutte('')
reverse (Buckethead ')
// 'daehtekcuB'

Nu har vi:

reverse (get6Characters (store bogstaver (getName ({navn: 'Buckethead'}))))
// 'TEKCUB'

Det kan blive lidt ... meget.

Rør til redning!

I stedet for at fastklemme funktioner inden for funktioner eller oprette en masse mellemvariabler, lad os røre alle tingene!

rør(
  getNavn,
  store bogstaver,
  get6Characters,
  baglæns
) ({navn: 'Buckethead'})
// 'TEKCUB'

Ren kunst. Det er som en todo-liste!

Lad os gå igennem det.

Til demo-formål bruger jeg en rørimplementering fra en af ​​Eric Elliotts funktionelle programmeringsartikler.

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

Jeg elsker denne lille one-liner.

Brug af hvileparametre, se min artikel om det, vi kan rør n funktioner. Hver funktion tager output fra den foregående, og det hele reduceres til en enkelt værdi.

Og du kan bruge det ligesom vi gjorde ovenfor.

rør(
  getNavn,
  store bogstaver,
  get6Characters,
  baglæns
) ({navn: 'Buckethead'})
// 'TEKCUB'

Jeg udvider røret og tilføjer nogle debugger-udsagn, og vi går linje for linje.

pipe = (... funktioner) => (værdi) => {
  debugger;
  returfunktioner
    .reduce ((currentValue, currentFunction) => {
       debugger;
       returstrømFunktion (nuværende værdi);
    }, værdi)
}

Ring rør med vores eksempel, og lad vidunderne udfolde sig.

Tjek de lokale variabler. funktioner er en matrix af de 4 funktioner, og værdien er {navn: 'Buckethead'}.

Da vi brugte hvileparametre (igen, se min artikel ), tillader pipe et hvilket som helst antal funktioner, der kan bruges. Det vil bare loope og ringe til hver enkelt.

På den næste debugger er vi inden for reducering. Det er her, nuværende værdi overføres til nuværende funktion og returneres.

Vi ser, at resultatet er 'Buckethead', fordi currentFunction returnerer egenskaben .name for ethvert objekt. Dette returneres i reducering, hvilket betyder, at det bliver den nye nuværende værdi næste gang. Lad os ramme den næste debugger og se.

Nu er nuværende værdi 'Buckethead', fordi det var det, der kom tilbage sidste gang. currentFunction er store, så 'BUCKETHEAD' vil være den næste aktuelle værdi.

Den samme idé, pluk 'BUCKETHEAD''s første 6 tegn og del dem ud til den næste funktion.

omvendt (‘. aedi emaS’)

Og du er færdig!

Hvad med at komponere ()?

Det er bare rør i den anden retning.

Så hvis du ønskede det samme resultat som vores pipe ovenfor, ville du gøre det modsatte.

komponere (
  baglæns,
  get6Characters,
  store bogstaver,
  getNavn,
) ({navn: 'Buckethead'})

Bemærk, hvordan getName sidst sidder i kæden, og omvendt er først?

Her er en hurtig implementering af komponering, igen med tilladelse fra den magiske Eric Elliott, fra den samme artikel.

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

Jeg overlader at udvide denne funktion med debuggers som en øvelse for dig. Leg med det, brug det, værdsæt det. Og vigtigst af alt, have det sjovt!

Indtil næste gang!

Pas på,
Yazeed Bzadough