Denne JavaScript-språkfunksjonen kan hjelpe deg med å rydde opp i koden din og vil gi deg en ny forståelse av hvordan funksjoner fungerer.

Curried-funksjoner kan bidra til å gjøre JavaScript-koden din mer lesbar og uttrykksfull. Karryteknikken er ideell når du ønsker å bryte ned kompleks logikk i mindre, selvstendige, mer håndterbare kodebiter.

Lær alt om curry-funksjoner i JavaScript, hvordan du bruker funksjonen currying-teknikken for å lage delvis anvendte funksjoner, samt virkelige brukstilfeller for både curried-funksjoner og delvis anvendte funksjoner.

Hva er currying?

Currying er oppkalt etter matematikeren Haskell B. Curry, og konseptet stammer fra Lambda-regning. Currying tar en funksjon som mottar mer enn én parameter og deler den opp i en rekke unære (én-parameter) funksjoner. Med andre ord, en curried funksjon tar bare én parameter om gangen.

Et grunnleggende eksempel på karrying

Nedenfor er et eksempel på en karriefunksjon:

functionbuildSandwich(ingredient1) {
return(ingredient2) => {
return(ingredient3) => {
return`${ingredient1},${ingredient2},${ingredient3}`
}
}
}

De buildSandwich() funksjon returnerer en annen funksjon - en anonym funksjon som mottar ingrediens2 argument. Deretter returnerer denne anonyme funksjonen en annen anonym funksjon som mottar ingrediens3. Til slutt returnerer denne siste funksjonen malen bokstavelig, en måte å formateringsstrenger i JavaScript.

Det du har laget er en nestet funksjon der hver funksjon kaller den under den til vi når slutten. Nå, når du ringer buildSandwich() og sender den en enkelt parameter, vil den returnere den delen av funksjonen hvis argumenter du ennå ikke har oppgitt:

console.log(buildSandwich("Bacon"))

Du kan se fra utdataene at buildSandwich returnerer en funksjon:

For å fullføre funksjonskallet, må du oppgi alle tre argumentene:

buildSandwich("Bacon")("Lettuce")("Tomato")

Denne koden sender "Bacon" til den første funksjonen, "Salat" til den andre, og "Tomat" til den siste funksjonen. Med andre ord buildSandwich() funksjonen er virkelig delt inn i tre funksjoner, der hver funksjon mottar bare én parameter.

Selv om det er helt gyldig å bruke karri med de tradisjonelle funksjonene, kan all hekking bli ganske stygg jo dypere du kommer. For å komme rundt dette kan du bruke pilfunksjoner og dra nytte av deres renere syntaks:

const buildMeal = ingred1 =>ingred2 =>ingred3 =>
`${ingred1}, ${ingred2}. ${ingred3}`;

Denne refaktorerte versjonen er mer kortfattet, en fordel ved å bruke pilfunksjoner vs vanlige funksjoner. Du kan kalle funksjonen på samme måte som du gjorde med den forrige:

buildMeal("Bacon")("Lettuce")("Tomato")

Delvis anvendte karrifunksjoner

Delvis brukte funksjoner er en vanlig bruk av karri. Denne teknikken innebærer å levere bare de nødvendige argumentene om gangen (i stedet for å levere alle argumentene). Hver gang du påkaller en funksjon ved å sende alle nødvendige parametere, sier du at du har "brukt" den funksjonen.

La oss se på et eksempel:

const multiply = (x, y) => x * y;

Nedenfor er curriedversjonen av multiplisere:

const curriedMultiply = x =>y => x * y;

De curriedMultiply() funksjonen mottar x argument for den første funksjonen og y for den andre funksjonen multipliserer den begge verdiene.

For å opprette den første delvis brukte funksjonen, ring curriedMultiple() med den første parameteren og tilordne den returnerte funksjonen til en variabel:

const timesTen = curriedMultiply(10)

På dette tidspunktet har koden "delvis brukt". curriedMultiply() funksjon. Så når som helst du vil ringe ganger ti(), du trenger bare å gi det ett tall, og tallet vil automatisk multipliseres med 10 (som er lagret i den brukte funksjonen):

console.log(timesTen(8)) // 80

Dette lar deg bygge på en enkelt kompleks funksjon ved å lage flere tilpassede funksjoner fra den, hver med sin egen funksjonalitet låst inn.

Ta en titt på et eksempel som er nærmere et ekte nettutviklingsbruk. Nedenfor har du en updateElemText() funksjon som tar et elements id på den første samtalen, innholdet på den andre samtalen, og deretter oppdaterer elementet basert på id og innholdet du har levert det:

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!")

Funksjonssammensetning Med Curried-funksjoner

En annen vanlig bruk av karry er funksjonssammensetning. Dette lar deg kalle opp små funksjoner, i en bestemt rekkefølge, og kombinere dem til en enkelt, mer kompleks funksjon.

For eksempel, i et hypotetisk e-handelsnettsted, her er tre funksjoner som du kanskje vil kjøre etter hverandre (i nøyaktig rekkefølge):

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.`);
}

Legg merke til at denne koden bruker la nøkkelord for å definere completeOrder() funksjon. Dette lar deg tilordne en verdi til variabelen og er en del av hvordan scoping fungerer i JavaScript.

Deretter må du kalle opp funksjonene i omvendt rekkefølge (fra innsiden til utsiden) fordi du vil legge til kundene først:

completeOrder = (processOrder(completeOrder));
completeOrder = (addCustomer(completeOrder));
completeOrder("1000")

Dette vil gi deg følgende utgang:

Hvis du skulle skrive funksjonene ovenfor på vanlig måte, vil koden se omtrent slik ut:

functionaddCustomer(...args) {
returnfunctionprocessOrder(...args) {
returnfunctioncompleteOrder(...args) {
// end
}
}
}

Når du ringer addCustomer() funksjon og pass inn argumentene, starter du fra innsiden og jobber deg ut til toppen av funksjonen.

Konverter en normal funksjon til en karrifunksjon med en karrifunksjon

Hvis du planlegger å bruke karrifunksjoner mye, kan du effektivisere prosessen med en hjelpefunksjon.

Denne funksjonen vil konvertere enhver normal funksjon til en curried funksjon. Den bruker rekursjon for å håndtere et hvilket som helst antall argumenter.

const curry = (fn) => {
return curried = (...args) => {
if (fn.length !== args.length) {
return curried.bind(null, ...args)
}

return fn(...args);
}
}

Denne funksjonen vil akseptere enhver standard skrevet funksjon som mottar mer enn én parameter, og returnerer en curried versjon av den funksjonen. For å se det i aksjon, bruk denne eksempelfunksjonen som tar tre parametere og legger dem sammen:

const total = (x, y, z) => x + y + z

For å konvertere denne funksjonen, ring karri() funksjon og bestått Total som argument:

const curriedTotal = curry(total)

Nå for å kalle funksjonen, trenger du bare å sende inn alle argumentene:

console.log(curriedTotal(10)(20)(30)) // 60

Mer om funksjoner i JavaScript

JavaScripts funksjoner er ekstremt fleksible, og curry funksjoner er bare en liten del av det. Det finnes mange andre typer funksjoner som pilfunksjoner, konstruktørfunksjoner og anonyme funksjoner. Å gjøre deg kjent med disse funksjonene og komponentene deres er nøkkelen til å mestre JavaScript.