Această caracteristică a limbajului JavaScript vă poate ajuta să vă ordonați codul și vă va oferi o nouă apreciere a modului în care funcționează funcțiile.
Funcțiile curry vă pot ajuta să vă faceți codul JavaScript mai lizibil și mai expresiv. Tehnica de curry este ideală atunci când doriți să descompuneți logica complexă în bucăți de cod mai mici, autonome și mai ușor de gestionat.
Aflați totul despre funcțiile curry în JavaScript, cum să utilizați tehnica de curry al funcției pentru a crea funcții parțial aplicate, precum și cazuri de utilizare din viața reală, atât pentru funcții curry, cât și parțial aplicate funcții.
Ce este curry?
Currying este numit după matematicianul Haskell B. Curry, iar conceptul derivă din calculul Lambda. Currying ia o funcție care primește mai mult de un parametru și îl descompune într-o serie de funcții unare (cu un singur parametru). Cu alte cuvinte, o funcție cu curry ia doar un parametru la un moment dat.
Un exemplu de bază de curry
Mai jos este un exemplu de funcție curry:
functionbuildSandwich(ingredient1) {
return(ingredient2) => {
return(ingredient3) => {
return`${ingredient1},${ingredient2},${ingredient3}`
}
}
}
The buildSandwich() funcția returnează o altă funcție — o funcție anonimă care primește ingredient 2 argument. Apoi, această funcție anonimă returnează o altă funcție anonimă care primește ingredient 3. În cele din urmă, această ultimă funcție returnează literalul șablonului, o modalitate de formatarea șirurilor în JavaScript.
Ceea ce ați creat este o funcție imbricată în care fiecare funcție o apelează pe cea de sub ea până ajungem la sfârșit. Acum, când suni buildSandwich() și transmiteți-i un singur parametru, va returna partea funcției ale cărei argumente nu le furnizați încă:
console.log(buildSandwich("Bacon"))
Puteți vedea din rezultat că buildSandwich returnează o funcție:
Pentru a finaliza apelul funcției, ar trebui să furnizați toate cele trei argumente:
buildSandwich("Bacon")("Lettuce")("Tomato")
Acest cod trece „Slănină” la prima funcție, „Salată verde” la a doua și „Tomate” la ultima funcție. Cu alte cuvinte, buildSandwich() funcția este într-adevăr împărțită în trei funcții, fiecare funcție primind doar un parametru.
Deși este perfect valid să curry folosind funcțiile tradiționale, toate cuiburile pot deveni destul de urâte cu cât ajungi mai adânc. Pentru a ocoli acest lucru, puteți utiliza funcțiile de săgeți și puteți profita de sintaxa lor mai curată:
const buildMeal = ingred1 =>ingred2 =>ingred3 =>
`${ingred1}, ${ingred2}. ${ingred3}`;
Această versiune refactorizată este mai concisă, un avantaj al utilizării funcții săgeți vs funcții obișnuite. Puteți apela funcția în același mod în care ați făcut-o cu cea anterioară:
buildMeal("Bacon")("Lettuce")("Tomato")
Funcții curry parțial aplicate
Funcțiile parțial aplicate sunt o utilizare comună a curry. Această tehnică presupune furnizarea doar a argumentelor necesare la un moment dat (mai degrabă decât furnizarea tuturor argumentelor). Ori de câte ori invocați o funcție trecând toți parametrii necesari, spuneți că ați „aplicat” acea funcție.
Să ne uităm la un exemplu:
const multiply = (x, y) => x * y;
Mai jos este versiunea cu curry a înmulțirii:
const curriedMultiply = x =>y => x * y;
The curryMultiply() funcția primește X argument pentru prima funcție și y pentru a doua funcție, apoi înmulțește ambele valori.
Pentru a crea prima funcție parțial aplicată, apelați curryMultiple() cu primul parametru și atribuiți funcția returnată unei variabile:
const timesTen = curriedMultiply(10)
În acest moment, codul a „aplicat parțial”. curryMultiply() funcţie. Deci oricând vrei să suni timesTen(), trebuie doar să-i treci un număr și numărul va fi înmulțit automat cu 10 (care este stocat în cadrul funcției aplicate):
console.log(timesTen(8)) // 80
Acest lucru vă permite să construiți pe o singură funcție complexă prin crearea mai multor funcții personalizate din ea, fiecare cu propriile sale funcționalități blocate.
Aruncă o privire la un exemplu care este mai aproape de un caz de utilizare real al dezvoltării web. Mai jos ai un updateElemText() funcţie care ia a unui element id la primul apel, conținutul la al doilea apel și apoi actualizează elementul pe baza id și conținutul pe care l-ați furnizat:
const updateElemText = id = content
=> document.querySelector(`#${id}`).textContent = content// Lock the element's id into the function:
const updateHeaderText = updateElemText('header')
// Update the header text
updateHeaderText("Hello World!")
Compoziția funcției cu funcții curry
O altă utilizare comună a curryului este compoziția funcției. Acest lucru vă permite să apelați funcții mici, într-o anumită ordine, și să le combinați într-o singură funcție, mai complexă.
De exemplu, într-un site web de comerț electronic ipotetic, iată trei funcții pe care ați putea dori să le rulați una după alta (în ordine precisă):
const addCustomer = fn =>(...args) => {
console.log("Saving customer info")
return fn(...args)
}const processOrder = fn =>(...args) => {
console.log(`processing order #${args[0]}`)
return fn(...args);
}
let completeOrder = (...args) => {
console.log(`Order #${[...args].toString()} completed.`);
}
Observați că acest cod folosește lăsa cuvânt cheie pentru a defini completeOrder() funcţie. Acest lucru vă permite să reatribuiți o valoare variabilei și face parte din cum funcționează scoping-ul în JavaScript.
Apoi, trebuie să apelați funcțiile în ordine inversă (din interior spre exterior), deoarece doriți să adăugați mai întâi clienții:
completeOrder = (processOrder(completeOrder));
completeOrder = (addCustomer(completeOrder));
completeOrder("1000")
Acest lucru vă va oferi următoarea ieșire:
Dacă ar fi să scrieți funcțiile de mai sus în mod obișnuit, codul va arăta cam așa:
functionaddCustomer(...args) {
returnfunctionprocessOrder(...args) {
returnfunctioncompleteOrder(...args) {
// end
}
}
}
Când suni la addCustomer() funcția și introduceți argumentele, începeți din interior și vă îndreptați spre partea de sus a funcției.
Convertiți o funcție normală într-o funcție curry cu o funcție curry
Dacă intenționați să utilizați mult funcțiile curry, puteți simplifica procesul cu o funcție de ajutor.
Această funcție va converti orice funcție normală într-o funcție curry. Folosește recursiunea pentru a gestiona orice număr de argumente.
const curry = (fn) => {
return curried = (...args) => {
if (fn.length !== args.length) {
return curried.bind(null, ...args)
}
return fn(...args);
}
}
Această funcție va accepta orice funcție scrisă standard care primește mai mult de un parametru, returnând o versiune curry a acelei funcție. Pentru a-l vedea în acțiune, utilizați acest exemplu de funcție care ia trei parametri și îi adună:
const total = (x, y, z) => x + y + z
Pentru a converti această funcție, apelați curry() functioneaza si trece total ca argument:
const curriedTotal = curry(total)
Acum, pentru a apela funcția, trebuie doar să treceți toate argumentele:
console.log(curriedTotal(10)(20)(30)) // 60
Mai multe despre funcții în JavaScript
Funcțiile JavaScript sunt extrem de flexibile, iar funcțiile de curry sunt doar o mică parte din asta. Există multe alte tipuri de funcții, cum ar fi funcții săgeți, funcții de constructor și funcții anonime. Familiarizarea cu aceste funcții și componentele lor este cheia pentru stăpânirea JavaScript.