JavaScript-zelfstudie: functies van hogere orde

Vorige week heb ik terloops de term "hogere-orde-functie" laten vallen als ik het over memo had. Hoewel ik me nu op mijn gemak voel om met zulke termen om te gooien, wist ik niet altijd wat ze betekenden. Deze week zullen we onderzoeken wat functies van een hogere orde zijn, enkele veelvoorkomende voorbeelden laten zien en leren hoe we onze eigen functies kunnen maken.

In wezen is een functie van hogere orde slechts een functie die een functie als argument accepteert of een functie retourneert. Dit is mogelijk in JavaScript dankzij eersteklas functies, wat betekent dat functies in JavaScript kunnen worden doorgegeven zoals elke andere variabele. Hoewel dit vrij eenvoudig klinkt, telegrafeert het niet helemaal het soort kracht dat je hebt met eersteklas functies.

Als je JavaScript schrijft, heb je waarschijnlijk functies van een hogere orde gebruikt en niet eens opgemerkt. Als je ooit een forlus hebt vervangen door een arraymethode, heb je functies van hogere orde gebruikt. Als je ooit de resultaten van een AJAX-aanroep (zonder async/ await) hebt gebruikt, heb je functies van een hogere orde gebruikt (zowel beloften als terugbellen hebben betrekking op functies van hogere orde). Als je ooit een React-component hebt geschreven die een lijst met items weergeeft, heb je functies van hogere orde gebruikt. Laten we die voorbeelden eens bekijken:

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

// In plaats van deze for loop ...

voor (let i = 0; i <items.length - 1; i ++) {

  console.log (items [i]);

}

// We kunnen forEach een functie van hogere orde gebruiken

// (forEach neemt een functie als argument)

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

// Terugbelverzoeken of beloftes, als u iets doet

// asynchrone verzoeken, u gebruikt

// hogere orde functies

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

  putImageOnScreen (response.file);

});

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

  putImageOnScreen (response.file);

});

// In de React-component hieronder wordt map gebruikt,

// dat is een functie van hogere orde

const myListComponent = (rekwisieten) => {

  terugkeer (

   

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

            terugkeer (

  • {item}
  • )

          })}

      );

    };

Dat zijn voorbeelden van functies van een hogere orde die functies accepteren als argumenten, maar er zijn er ook veel die functies retourneren. Als je ooit een functieaanroep hebt gezien met twee sets haakjes, is dat een functie van een hogere orde. Dit soort dingen was vroeger minder gebruikelijk, maar als je überhaupt met Redux werkt, heb je waarschijnlijk de connectfunctie gebruikt, wat een functie van hogere orde is:

export standaard connect (mapStateToProps, mapDispatchToProps) (MyComponent);

In het bovenstaande geval bellen we connectmet twee argumenten en het retourneert een functie, die we onmiddellijk aanroepen met één argument. Mogelijk hebt u ook een eenvoudige logboekregistratiebibliotheek gezien (of geschreven) die functies als retourwaarden gebruikt. In het onderstaande voorbeeld maken we een logger die de context registreert vóór het bericht:

const createLogger = (context) => {

  return (msg) => {

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

  }

};

const log = createLogger ('myFile');

log ('Een heel belangrijk bericht');

// logt uit "myFile: een heel belangrijk bericht"

Het bovenstaande voorbeeld illustreert een deel van de kracht van functies van een hogere orde (zie ook mijn vorige bericht over memoisatie). Merk op dat dit createLoggereen argument accepteert waarnaar we verwijzen in de hoofdtekst van de functie die we retourneren. Die geretourneerde functie, die we aan de variabele toewijzen log, heeft nog steeds toegang tot het contextargument omdat het binnen het bereik was waar de functie was gedefinieerd.

Leuk weetje: verwijzingen contextworden mogelijk gemaakt door sluitingen. Ik zal hier niet ingaan op afsluitingen omdat ze hun eigen post verdienen, maar ze kunnen worden gebruikt in combinatie met functies van hogere orde voor een aantal echt interessante effecten.

Het gebruik van sluitingen in combinatie met functies van een hogere orde was bijvoorbeeld de enige manier waarop we 'privé'- of fraudebestendige variabelen in JavaScript konden hebben:

let protectedObject = (function () {

  laat myVar = 0;

  terug {

    get: () => myVar,

    increment: () => myVar ++,

  };

}) ();

protectedObject.get (); // retourneert 0

protectedObject.increment ();

protectedObject.get (); // retourneert 1

myVar = 42; // oeps! je hebt zojuist een globale variabele gemaakt

protectedObject.get (); // retourneert nog steeds 1

Maar laten we niet meeslepen. Voor functies van hogere orde is niets speciaals nodig, zoals sluitingen. Het zijn gewoon functies die andere functies als argumenten aannemen of functies retourneren. Punt. Als je meer voorbeelden wilt of verder wilt lezen, bekijk dan het hoofdstuk over functies van hogere orde in "Eloquent JavaScript" van Marijn Haverbeke.

Vragen of opmerkingen? Neem gerust contact op via Twitter: @freethejazz.