Programmering

JavaScript-tutorial: Funktioner i højere ordre

I sidste uge droppede jeg tilfældigt udtrykket "højere ordensfunktion", når jeg talte om memoization. Mens jeg har det godt med at kaste ord som det nu, vidste jeg ikke altid, hvad de betød. Denne uge undersøger vi, hvad højere ordensfunktioner er, viser nogle almindelige eksempler og lærer, hvordan vi kan arbejde på at skabe vores egne.

I sin kerne er en højere ordensfunktion bare en funktion, der accepterer en funktion som et argument eller returnerer en funktion. Dette er muligt i JavaScript takket være førsteklasses funktioner, hvilket betyder, at funktioner i JavaScript kan videregives som enhver anden variabel. Selvom dette lyder ret ligetil, telegraferer det ikke helt den slags magt, du har med førsteklasses funktioner.

Hvis du skriver JavaScript, har du sandsynligvis brugt højere ordensfunktioner og ikke engang bemærket. Hvis du nogensinde har udskiftet en til loop med en matrixmetode, har du brugt højere ordensfunktioner. Hvis du nogensinde har brugt resultaterne af et AJAX-opkald (uden asynkronisering/vente), har du brugt højere ordensfunktioner (både løfter og tilbagekald involverer højere ordensfunktioner). Hvis du nogensinde har skrevet en React-komponent, der viser en liste over emner, har du brugt højere ordensfunktioner. Lad os se disse eksempler:

const items = ['a', 'b', 'c', 'd', 'e']

// I stedet for dette til løkke ....

for (lad i = 0; i <items.length - 1; i ++) {

console.log (emner [i]);

}

// Vi kan bruge forEach, en højere ordensfunktion

// (forEach tager en funktion som et argument)

items.forEach ((item) => console.log (item));

// Tilbagekald eller løfter, hvis du afgiver

// asynkrone anmodninger, du bruger

// højere ordensfunktioner

get ('// aws.random.cat/meow', (response) => {

putImageOnScreen (respons.file);

});

get ('// random.dog/woof.json').then((response) => {

putImageOnScreen (respons.file);

});

// I reaktionskomponenten nedenfor bruges kort,

// som er en højere ordensfunktion

const myListComponent = (rekvisitter) => {

Vend tilbage (

   

    {props.items.map ((item) => {

    Vend tilbage (

  • {vare}
  • )

          })}

      );

    };

Disse er eksempler på funktioner af højere orden, der accepterer funktioner som argumenter, men mange af dem returnerer også funktioner. Hvis du nogensinde har set et funktionsopkald, der har to sæt parenteser, er det en højere ordensfunktion. Denne slags ting plejede at være mindre almindelige, men hvis du overhovedet arbejder med Redux, har du sandsynligvis brugt Opret forbindelse funktion, som er en højere ordens funktion:

eksport af standardtilslutning (mapStateToProps, mapDispatchToProps) (MyComponent);

I ovenstående tilfælde kalder vi Opret forbindelse med to argumenter, og det returnerer en funktion, som vi straks kalder med et argument. Du har muligvis også set (eller skrevet) et simpelt logbibliotek, der bruger funktioner som returværdier. I eksemplet nedenfor opretter vi en logger, der logger sin kontekst før meddelelsen:

const createLogger = (context) => {

returnere (msg) => {

console.log (`$ {context}: $ {msg}`);

  }

};

const log = createLogger ('myFile');

log ('En meget vigtig besked');

// logger ud "myFile: En meget vigtig besked"

Eksemplet ovenfor begynder at illustrere nogle af styrken i funktioner af højere orden (se også mit tidligere indlæg om memoization). Noter det createLogger tager et argument, som vi henviser til i kroppen af ​​den funktion, vi returnerer. Den returnerede funktion, som vi tildeler variablen log, kan stadig få adgang til sammenhæng argument, fordi det var i omfang, hvor funktionen blev defineret.

Sjov kendsgerning: Referencer sammenhæng muliggøres ved lukninger. Jeg går ikke ind på lukninger her, fordi de fortjener deres eget indlæg, men de kan bruges i forbindelse med højere ordensfunktioner til nogle virkelig interessante effekter.

For eksempel var brug af lukninger sammen med højere ordensfunktioner den eneste måde, vi kunne have "private" eller manipulationssikre variabler i JavaScript:

lad protectedObject = (funktion () {

lad myVar = 0;

Vend tilbage {

få: () => myVar,

forøgelse: () => myVar ++,

  };

})();

protectedObject.get (); // returnerer 0

protectedObject.increment ();

protectedObject.get (); // returnerer 1

myVar = 42; // hops! du har lige oprettet en global variabel

protectedObject.get (); // returnerer stadig 1

Lad os dog ikke blive båret af. Funktioner i højere ordre kræver ikke noget fancy som lukninger. De er simpelthen funktioner, der tager andre funktioner som argumenter, eller som returnerer funktioner. Fuldt stop. Hvis du ønsker flere eksempler eller yderligere læsning, kan du tjekke kapitlet om højere ordensfunktioner i “Eloquent JavaScript” af Marijn Haverbeke.

Spørgsmål eller kommentarer? Du er velkommen til at nå ud på Twitter: @freethejazz.