Vodič za JavaScript: Funkcije višeg reda

Prošli sam tjedan neobavezno izbacio izraz "funkcija višeg reda" kada sam govorio o pamćenju. Iako mi je sada ugodno bacati takve izraze, nisam uvijek znao što oni znače. Ovaj ćemo tjedan ispitati što su funkcije višeg reda, pokazati nekoliko uobičajenih primjera i naučiti kako krenuti u stvaranje vlastitih.

U osnovi je funkcija višeg reda samo funkcija koja prihvaća funkciju kao argument ili vraća funkciju. To je moguće u JavaScript-u zahvaljujući prvoklasnim funkcijama, što znači da se funkcije u JavaScript-u mogu prenositi poput bilo koje druge varijable. Iako ovo zvuči prilično izravno, ne telegrafira baš onakvu kakvu snagu imate s prvoklasnim funkcijama.

Ako pišete JavaScript, vjerojatno ste koristili funkcije višeg reda i niste to ni primijetili. Ako ste ikada zamijenili forpetlju metodom niza, koristili ste funkcije višeg reda. Ako ste ikada koristili rezultate AJAX poziva (bez async/ await), koristili ste funkcije višeg reda (i obećanja i povratni pozivi uključuju funkcije višeg reda). Ako ste ikada napisali komponentu React koja prikazuje popis stavki, koristili ste funkcije višeg reda. Pogledajmo te primjere:

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

// Umjesto ove for petlje ....

za (neka je i = 0; i <items.length - 1; i ++) {

  console.log (stavke [i]);

}

// Možemo koristiti forEach, funkciju višeg reda

// (forEach uzima funkciju kao argument)

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

// Povratni pozivi ili obećanja, ako dajete

// asinkroni zahtjevi koje koristite

// funkcije višeg reda

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

  putImageOnScreen (response.file);

});

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

  putImageOnScreen (response.file);

});

// U donjoj komponenti React koristi se karta,

// što je funkcija višeg reda

const myListComponent = (rekviziti) => {

  povratak (

   

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

            povratak (

  • {artikal}
  • )

          })}

      );

    };

To su primjeri funkcija višeg reda koje funkcije prihvaćaju kao argumente, ali dosta ih vraća i funkcije. Ako ste ikada vidjeli poziv funkcije koji ima dva skupa zagrada, to je funkcija višeg reda. Takve su stvari nekad bile rjeđe, ali ako uopće radite s Reduxom, vjerojatno ste koristili connectfunkciju, koja je funkcija višeg reda:

izvoz zadane veze (mapStateToProps, mapDispatchToProps) (MyComponent);

U gornjem slučaju pozivamo connects dva argumenta i vraća funkciju koju odmah pozivamo s jednim argumentom. Možda ste vidjeli i (ili napisali) jednostavnu knjižnicu dnevnika koja koristi funkcije kao povratne vrijednosti. U primjeru u nastavku stvorit ćemo zapisnik koji bilježi svoj kontekst prije poruke:

const createLogger = (context) => {

  povratak (poruka) => {

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

  }

};

const log = createLogger ('myFile');

log ('Vrlo važna poruka');

// odjavljuje se "myFile: Vrlo važna poruka"

Gornji primjer započinje s ilustracijom neke snage funkcija višeg reda (vidi također moj prethodni post o memoizaciji). Napomena koja createLoggeruzima argument na koji se pozivamo u tijelu funkcije koju vraćamo. Ta vraćena funkcija koju dodijelimo varijabli logi dalje može pristupiti contextargumentu jer je bio u opsegu gdje je funkcija definirana.

Zabavna činjenica: Upućivanje contextje omogućeno zatvaranjem. Ovdje neću ulaziti u zatvaranja jer zaslužuju vlastiti post, ali mogu se koristiti zajedno s funkcijama višeg reda za neke stvarno zanimljive efekte.

Na primjer, upotreba zatvarača zajedno s funkcijama višeg reda nekad je bio jedini način na koji smo mogli imati "privatne" ili neovlaštene varijable u JavaScriptu:

neka protectedObject = (function () {

  neka myVar = 0;

  povratak {

    get: () => myVar,

    priraštaj: () => myVar ++,

  };

}) ();

protectedObject.get (); // vraća 0

protectedObject.increment ();

protectedObject.get (); // vraća 1

mojVar = 42; // ups! upravo ste stvorili globalnu varijablu

protectedObject.get (); // i dalje vraća 1

Ipak, nemojmo se zanositi. Funkcije višeg reda ne zahtijevaju ništa otmjeno poput zatvaranja. To su jednostavno funkcije koje druge funkcije uzimaju kao argumente ili koje vraćaju funkcije. Točka. Ako želite još primjera ili daljnje čitanje, pogledajte poglavlje o funkcijama višeg reda u “Elokventnom JavaScriptu” Marijn Haverbeke.

Pitanja ili komentari? Slobodno se obratite na Twitteru: @freethejazz.