JavaScript-functies, bereik en closures

Leer JavaScript-code onder te brengen in herbruikbare functies. Schrijf functiedeclaraties, functie-expressies en pijlfuncties; geef waarden door met parameters, standaardwaarden en restparameters; en geef resultaten terug met return. Voorspel waar je een variabele kunt gebruiken met blokbereik, functiebereik en globaal bereik, gebruik closures om functies een eigen geheugen te geven en geef functies als callbacks door aan andere functies om flexibele code met hogere-ordefuncties te schrijven.

BeginnerLes 3 van 9 in Cursus JavaScript programmeren: DOM, events, asynchrone code en modules

Wat je leert

  1. Breng een herbruikbaar stuk code onder in een functie, roep die aan met argumenten en kies tussen een functiedeclaratie, een functie-expressie en een pijlfunctie.
    • Schrijf een functiedeclaratie en roep de functie aan
      Definieer een benoemde functie met het sleutelwoord function, roep de functie aan en leg uit waarom functies code korter, duidelijker en gemakkelijker te wijzigen maken.
    • Sla een functie op in een variabele met een functie-expressie
      Behandel functies als waarden: maak een functie-expressie, wijs die toe aan een variabele en leg uit hoe die van een declaratie verschilt in hoisting en naamgeving.
    • Schrijf pijlfuncties
      Gebruik de korte pijlsyntaxis, weet wanneer een pijlfunctie automatisch een waarde teruggeeft en leg uit hoe pijlfuncties verschillen van functies die met function zijn geschreven.
  2. Ontwerp wat een functie ontvangt en teruggeeft: koppel argumenten aan parameters, stel standaardwaarden in, accepteer een willekeurig aantal argumenten, geef resultaten terug en volg hoe aanroepen binnen elkaar worden uitgevoerd.
    • Koppel argumenten aan parameters
      Leg uit hoe de waarden in een aanroep bij de parameters van de functie terechtkomen, wat er gebeurt bij te weinig of te veel argumenten en welke gegevens van de aanroeper een functie kan wijzigen.
    • Stel standaardwaarden in en accepteer een willekeurig aantal argumenten
      Geef parameters standaardwaarden, verzamel een willekeurig aantal argumenten met een restparameter en pak een array uit in afzonderlijke argumenten.
    • Geef resultaten terug vanuit een functie
      Geef een waarde terug met return, gebruik het resultaat in verdere code en onderscheid een waarde teruggeven van een waarde tonen of iets buiten de functie wijzigen.
    • Volg functieaanroepen via de aanroepstapel
      Volg de volgorde waarin geneste aanroepen worden uitgevoerd en terugkeren, en schrijf een eenvoudige recursieve functie met een basisgeval.
  3. Voorspel waar een variabele zichtbaar is door de regels voor blokbereik, functiebereik en globaal bereik toe te passen, evenals de regels voor functies die binnen andere functies zijn geschreven.
    • Onderscheid blokbereik, functiebereik en globaal bereik
      Leg het bereik uit van een variabele die met let, const of var is gedeclareerd en gebruik lokale variabelen om functies onafhankelijk van elkaar te houden.
    • Voorspel naar welke variabele een naam verwijst
      Volg de bereikketen om de variabele achter een naam te vinden, herken overschaduwing en leg hoisting en de tijdelijke dode zone uit.
  4. Leg uit hoe een functie toegang houdt tot de variabelen eromheen nadat de buitenste functie is beëindigd en gebruik dat om functiefabrieken en privétoestand op te bouwen.
    • Leg uit wat een closure onthoudt
      Beschrijf hoe een functie toegang houdt tot de variabelen van het bereik waarin die is gemaakt, zelfs nadat de buitenste functie is teruggekeerd.
    • Gebruik closures voor functiefabrieken en privétoestand
      Bouw functiefabrieken, houd gegevens privé achter functies en voorkom de klassieke fout met closures in een lus.
  5. Gebruik functies als waarden: geef ze als callbacks door aan andere functies, gebruik en schrijf hogere-ordefuncties en bouw nieuwe functies op uit bestaande functies.
    • Geef een callback door aan een functie
      Geef een functie als argument door aan een andere functie, schrijf functies die een callback aanroepen en geef de functie zelf door in plaats van haar resultaat.
    • Gebruik en schrijf hogere-ordefuncties
      Herken hogere-ordefuncties, gebruik de arraymethoden die callbacks accepteren en schrijf zelf een functie die een functie als invoer accepteert.
    • Bouw nieuwe functies op uit bestaande functies
      Schrijf hogere-ordefuncties die andere functies omhullen, combineren of vooraf van argumenten voorzien en gebruik closures om de ontvangen functie te onthouden.

JavaScript-functies: uitleg

5 hoofdstukken

1

Definieer functies in drie vormen en roep ze aan

Functies maken van herhaalde instructies benoemde taken. Je leest en schrijft drie veelvoorkomende vormen en bepaalt vervolgens of een regel een functie maakt, opslaat of aanroept. Kleine verschillen in syntaxis zijn van belang: een declaratie is vroeg beschikbaar, terwijl een opgeslagen expressie eerst moet worden geïnitialiseerd. Ook kan het functielichaam van een pijlfunctie bepalen of een resultaat wordt teruggegeven. Deze verschillen bereiden je erop voor om functies als gewone waarden door te geven.

1.1 Schrijf een functiedeclaratie en roep de functie aan

Een functie geeft een taak een naam en slaat de instructies op om die uit te voeren. Als je de functie definieert, worden die instructies niet uitgevoerd. Een aanroep voert ze uit en een volgende aanroep voert ze opnieuw uit met nieuwe invoer.

Schrijf de definitie

Een declaratie heeft het sleutelwoord function, een naam, ronde haakjes voor parameters en accolades voor het functielichaam:

function greet(name) {
  console.log("Hello, " + name + "!");
}

Hier is name een parameter: een lokale naam voor de invoer die elke aanroep levert. Het functielichaam voegt die invoer samen met de omringende tekst en toont het resultaat. De sluitaccolade geeft het einde van de definitie aan; de uitvoering gaat verder met de volgende instructie daarbuiten.

Een functie zonder invoer heeft nog steeds ronde haakjes nodig. Zo definieert function sayHi() { console.log("Hi"); } een taak met een lege parameterlijst. De accolades horen bij de definitie; de ronde haakjes na een naam horen zowel bij definities als bij aanroepen en hebben daar verschillende taken.

Voer de taak uit
greet("Amira");
greet("Li");

De eerste aanroep geeft name de waarde "Amira" en toont “Hello, Amira!”. De tweede begint een nieuwe aanroep met name gelijk aan "Li" en toont “Hello, Li!”. De definitie wordt gedeeld; de invoer hoort bij de afzonderlijke aanroep.

greet op zichzelf verwijst naar de functiewaarde. Het functielichaam wordt niet uitgevoerd. Dit verschil is van belang wanneer een regel niets lijkt te doen: sayHi; leest een functiewaarde en gooit die weg, terwijl sayHi(); “Hi” toont.

Vervang gekopieerde instructies

Stel dat meerdere rapporten een kop tussen lijnen nodig hebben:

function printHeading(title) {
  console.log("-----");
  console.log(title);
  console.log("-----");
}

printHeading("Report");
printHeading("Totals");

De eerste aanroep toont een lijn, “Report” en nog een lijn. De tweede toont hetzelfde kader rond “Totals”. Om de lijnstijl te wijzigen, pas je de twee instructies die lijnen tonen in deze ene definitie aan. Zonder de functie zou elke gekopieerde kop afzonderlijk moeten worden aangepast.

Kies een naam die aangeeft wat één aanroep doet. printHeading beschrijft een handeling; isValidEmail benoemt een ja-neecontrole. Gebruik camelCase, met een kleine letter aan het begin van het eerste woord en hoofdletters aan het begin van volgende woorden. Als een voorgestelde naam twee afzonderlijke taken met “en” verbindt, overweeg dan elke taak een eigen functie te geven.

Lees code die een declaratie vroeg aanroept

Declaraties worden klaargezet voordat de omringende code wordt uitgevoerd. Dit gedrag heet hoisting:

sayHi();
function sayHi() {
  console.log("Hi");
}

De aanroep werkt binnen het bereik van de declaratie, ook al staat de definitie verderop. Hoisting zorgt er niet voor dat het functielichaam vroeg wordt uitgevoerd; het maakt de functie beschikbaar voor een aanroep.

Controleer de spelling en het gebruik van hoofdletters als een aanroep mislukt. Greet() en greet() zijn verschillende namen. Als je een niet-gedeclareerde greeet() aanroept, krijg je een ReferenceError; het weglaten van de haakjes voor de aanroep kan ongemerkt misgaan, omdat het alleen lezen van een bestaande functie geldige code is.

Belangrijkste punten

  • Een functie definiëren slaat instructies op; een functie aanroepen voert ze uit.
  • Roep een functie aan met ronde haakjes, ook als er geen argumenten zijn.
  • Een declaratie is binnen hetzelfde bereik beschikbaar vóór de plaats waar die is geschreven.
  • Geef één duidelijke taak een naam, zodat herhaalde code één plaats heeft om te wijzigen.

1.2 Sla een functie op in een variabele met een functie-expressie

Functies zijn waarden. Je kunt een functie in een variabele bewaren, de referentie kopiëren, de functie doorgeven aan een andere functie of haar teruggeven. Een functie-expressie maakt die waarde op een plaats waar een expressie wordt verwacht.

Sla een functie op
const square = function (n) {
  return n * n;
};

const answer = square(4);

De expressie na = maakt een functie. De toewijzing slaat die op in square; de latere aanroep geeft 16 terug. Volgens de opmaakconventie die hier wordt gebruikt, eindigt deze instructie met een puntkomma.

De positie van function onderscheidt de vormen. Een definitie die zelfstandig is geschreven als function square(n) { ... } is een declaratie. Een functie die na = of direct als argument van een aanroep is geschreven, is een expressie. Beide gewone functievormen kunnen parameters accepteren en waarden teruggeven.

Gebruik const voor een functievariabele als de waarde gelijk moet blijven. square(5) aanroepen is toegestaan; square = 5; toewijzen veroorzaakt een TypeError. De constante beschermt de variabele tegen vervanging. Die verhindert niet dat je de functie herhaaldelijk aanroept.

Bewaar een functie of het resultaat ervan
const sq = square;
const result = square(3);

sq verwijst naar dezelfde functie als square. De aanroep sq(3) geeft 9 terug. result bevat het getal 9 dat één aanroep heeft teruggegeven. Je kunt dit getal niet als functie aanroepen. typeof square en typeof sq zijn "function"; typeof result is "number".

Het helpt om een toewijzing van rechts naar links te lezen: bepaal eerst of de rechterkant een functie maakt, naar een bestaande functie verwijst of een functie aanroept. De variabele links ontvangt die waarde. De referentie kopiëren maakt geen tweede onafhankelijke implementatie.

Wacht tot de toewijzing wordt uitgevoerd

Een declaratie en een opgeslagen expressie kun je op verschillende momenten aanroepen:

VormVóór de geschreven definitie of toewijzing
function square(n) { return n * n; }Aanroepbaar binnen het eigen bereik
const square = function (n) { return n * n; };square lezen veroorzaakt een ReferenceError
var square = function (n) { return n * n; };square is undefined; de functie aanroepen veroorzaakt een TypeError

Bij const of let kun je de naam niet gebruiken vóór initialisatie. Bij var bestaat de naam al vroeg, maar wordt de functiewaarde pas toegewezen wanneer de uitvoering de expressie bereikt. Hoisting van de variabele past geen hoisting toe op de toewijzing.

Geef een expressie een interne naam
const factorial = function fact(n) {
  return n <= 1 ? 1 : n * fact(n - 1);
};

De naam voor buiten de functie is factorial. De naam fact hoort binnen de functie en laat haar zichzelf aanroepen; code daarbuiten kan die interne naam niet direct gebruiken. De naam van de expressie kan ook aanroepsporen gemakkelijker leesbaar maken. Zo berekent factorial(3) 3 keer 2 keer 1 en geeft 6 terug.

Declaraties werken goed voor de belangrijkste benoemde taken in een script. Expressies passen op plaatsen waar code een functiewaarde nodig heeft, zoals bij een toewijzing aan een variabele of een argument. De keuze voor een expressie verandert hoe de waarde wordt gemaakt en opgeslagen, niet hoe je die met ronde haakjes aanroept.

Belangrijkste punten

  • Een functie-expressie maakt een functiewaarde binnen een andere expressie.
  • Als je square toewijst, kopieer je een functiereferentie; als je square(3) toewijst, sla je het resultaat op.
  • Een functie-expressie die in const is opgeslagen, kun je pas na initialisatie aanroepen.
  • Een functievariabele met var bevat undefined voordat de toewijzing wordt uitgevoerd.
  • Een benoemde expressie kan haar interne naam gebruiken om zichzelf aan te roepen.

1.3 Schrijf pijlfuncties

Pijlfuncties zijn functie-expressies met een kortere schrijfwijze. Wat ze teruggeven hangt af van wat na de pijl volgt, dus bekijk het functielichaam voordat je bepaalt wat een aanroep oplevert.

Kies de parametervorm
const sayHi = () => "hi";
const double = n => n * 2;
const add = (a, b) => a + b;

Zonder parameters zijn lege ronde haakjes nodig. Bij één eenvoudige parameter mogen de haakjes weg. Bij twee of meer zijn ze verplicht. Ook een parameter met een standaardwaarde of een restparameter heeft haakjes nodig: (n = 1) => n * 2 en (...nums) => nums.length zijn geldig.

De pijl scheidt de invoer van het functielichaam. const double = n => n * 2; maakt de functie en slaat die op; double(6) roept haar later aan en geeft 12 terug. Net als bij een const die een andere functie-expressie bevat, kun je double niet lezen voordat de initialisatieregel is uitgevoerd.

Geef een expressie terug of schrijf een blok
FunctielichaamVoorbeeldResultaat van de aanroep met 2 en 3
Expressie(a, b) => a + b5
Blok met return(a, b) => { return a + b; }5
Blok zonder return(a, b) => { a + b; }undefined

Een expressie als functielichaam geeft de waarde van die expressie automatisch terug. Accolades beginnen een blok met instructies. In een blok geeft het evalueren van een expressie de waarde niet terug aan de aanroeper; schrijf return expliciet.

Gebruik een blok wanneer de taak tussenstappen nodig heeft:

const describe = (n) => {
  const kind = n % 2 === 0 ? "even" : "odd";
  return n + " is " + kind;
};

Bij describe(7) is de voorwaarde onwaar, dus wordt kind gelijk aan "odd". De return voegt vervolgens het getal en de woorden samen tot “7 is odd”. Als je die return verwijdert, blijft de lokale berekening staan, maar krijgt de aanroeper undefined.

Geef een objectliteral terug

Een objectliteral gebruikt ook accolades. Zet die tussen ronde haakjes zodat de parser die als expressie behandelt:

const makePoint = (x, y) => ({ x: x, y: y });

makePoint(2, 5) geeft een object terug met x gelijk aan 2 en y gelijk aan 5. Zonder de ronde haakjes begint de eerste accolade een blok. De vorm met één eigenschap () => { value: 1 } geeft undefined terug; de vergelijkbare vorm met twee eigenschappen en een komma veroorzaakt een syntaxisfout. De haakjes veranderen hoe het functielichaam wordt gelezen.

Ken de grenzen van de kortere vorm

Pijlfuncties hebben geen eigen this of arguments en je kunt ze niet met new aanroepen om objecten te maken. Voor een eenvoudige berekening die geen this en geen arguments gebruikt, gedragen een pijlfunctie en een gewone functie-expressie zich hetzelfde. Als je elke gewone functie door een pijlfunctie vervangt, kan dat code veranderen die van die eigenschappen afhankelijk is.

Korte pijlfuncties zijn vooral leesbaar als callbacks. [1, 2, 3].map(n => n * 10) geeft een functie door die een getransformeerd element teruggeeft en levert [10, 20, 30] op. Als je die verandert in n => { n * 10; }, gaat elke teruggegeven waarde ongemerkt verloren.

Belangrijkste punten

  • Een expressie als functielichaam van een pijlfunctie geeft haar waarde automatisch terug.
  • Een instructieblok als functielichaam van een pijlfunctie heeft een expliciete return nodig om een berekende waarde terug te geven.
  • Zet een objectliteral die je vanuit een expressie als functielichaam van een pijlfunctie teruggeeft tussen ronde haakjes.
  • Lege parameterlijsten, lijsten met meerdere parameters en parameters met standaardwaarden of restparameters hebben ronde haakjes nodig.
  • Pijlfuncties hebben geen eigen this of arguments en kunnen geen constructor zijn.
2

Geef waarden door aan functies en ontvang resultaten

Een functieaanroep heeft een invoerkant en een uitvoerkant. Koppel argumenten aan parameters, verwerk optionele of flexibele invoer en volg de waarde die aan de aanroeper wordt teruggegeven. Je leert ook lokale wijzigingen onderscheiden van wijzigingen in een gedeelde array en volgt hoe geneste aanroepen pauzeren en hun werk hervatten. Hetzelfde model van aanroepen en terugkeren verklaart eenvoudige recursie, waarbij meerdere aanroepen van één functie wachten tot kleinere aanroepen klaar zijn.

2.1 Koppel argumenten aan parameters

De parameters van een functie geven namen aan de waarden die een aanroep levert. Om een aanroep te volgen, koppel je eerst invoer op positie en volg je daarna de bewerkingen in het functielichaam.

Koppel posities en typen
function area(width, height) {
  return width * height;
}

area(4, 2.5);

width en height zijn parameters; 4 en 2,5 zijn argumenten. Tijdens deze aanroep bevat width de waarde 4 en height de waarde 2,5, dus is het resultaat 10. Parameternamen worden niet gekoppeld aan namen van variabelen van de aanroeper. Als je bij divide(a, b) de aanroep divide(10, 2) verandert in divide(2, 10), verandert het resultaat van 5 in 0,2.

JavaScript dwingt geen aantal argumenten af. Bij area(4) blijft height gelijk aan undefined; vermenigvuldigen daarmee levert NaN op. area(4, 2, 99) geeft 8 terug omdat dit functielichaam het derde argument niet gebruikt. Een functie kan ervoor kiezen extra argumenten te verzamelen, maar ongebruikte extra argumenten veroorzaken niet automatisch een fout.

Ook typen zijn van belang, zelfs wanneer de aanroep wordt geaccepteerd. area("4", 2) geeft 8 terug omdat de vermenigvuldiging de tekst converteert. Een optelfunctie gedraagt zich anders: add("4", 2) geeft “42” terug wanneer het functielichaam return a + b; is. Als tekst een getal voorstelt, geeft add(Number("4"), 2) de waarde 6 terug.

Wijs een lokale parameter opnieuw toe

Elke parameter is lokaal voor de aanroep. Als je er een nieuw getal aan toewijst, wijs je de variabele van de aanroeper niet opnieuw toe:

let score = 5;
function reset(s) {
  s = 0;
}
reset(score);

De aanroep kopieert de waarde 5 naar s. De toewijzing verandert s in 0 en score blijft 5. Getallen, strings en booleaanse waarden volgen deze regel voor het kopiëren van waarden. Code daarbuiten kan s niet direct lezen; een geneste functie kan er via een closure toegang toe houden.

Wijzig een array via een gekopieerde referentie

Een arraywaarde is een referentie naar een array. Als je die waarde doorgeeft, wordt de referentie gekopieerd, zodat de aanroeper en de parameter dezelfde array kunnen bereiken:

const list = [1, 2];
function addItem(arr) {
  arr.push(3);
}
addItem(list);

list is nu [1, 2, 3]. De functie heeft list niet opnieuw toegewezen; ze heeft de array gewijzigd die beide namen bereiken. Een const-declaratie voorkomt dat je de opgeslagen referentie vervangt, maar niet dat je de inhoud van de array wijzigt.

Vergelijk dit met een lokale hertoewijzing:

function clearLocal(arr) {
  arr = [];
}
clearLocal(list);

Hierdoor verwijst alleen arr naar een nieuwe lege array. list verwijst nog steeds naar [1, 2, 3]. Vraag je af of een bewerking een bestaande array wijzigt, zoals push doet, of een naam een andere waarde geeft, zoals = doet.

Geef een nieuwe array terug als de invoer intact moet blijven
function withItem(arr, item) {
  return arr.concat(item);
}

withItem([1, 2], 3) levert [1, 2, 3] op als nieuwe array. De invoerarray blijft [1, 2]. Dit maakt de functie nuttig wanneer de aanroeper zowel de oude als de uitgebreide lijst nodig heeft. Maak de beoogde wijzigingen aan de invoer van een functie duidelijk via haar naam en gedrag, zodat aanroepers haar voorspelbaar kunnen gebruiken.

Belangrijkste punten

  • Argumenten worden op positie aan parameters gekoppeld.
  • Een ontbrekend argument levert undefined; ongebruikte extra argumenten zijn toegestaan.
  • Een parameter opnieuw toewijzen wijst de variabele van de aanroeper niet opnieuw toe.
  • Als je een array via een parameter wijzigt, verandert de gedeelde array.
  • Door een nieuwe array terug te geven, kun je de invoer behouden.

2.2 Stel standaardwaarden in en accepteer een willekeurig aantal argumenten

Standaardwaarden maken invoer optioneel; met restparameters kan een aanroep veel invoerwaarden leveren. Spreadsyntaxis verbindt een bestaande array met een functie die afzonderlijke argumenten verwacht.

Pas alleen bij undefined een standaardwaarde toe
function greet(name = "friend") {
  return "Hello, " + name;
}

greet() en greet(undefined) geven allebei “Hello, friend” terug. greet(null) geeft “Hello, null” terug en greet("") geeft “Hello, ” terug. Een standaardwaarde controleert op undefined, niet op elke waarde die leeg lijkt.

Standaardwaarden worden geëvalueerd wanneer een aanroep ze nodig heeft. Ze mogen eerdere parameters gebruiken: function makeBox(width, height = width) { return width * height; } geeft 9 terug voor makeBox(3) en 12 voor makeBox(3, 4). Het expliciete tweede argument vervangt de standaardwaarde voor die aanroep.

Zet verplichte invoer eerst. Met function total(amount, rate = 0.25) { return amount + amount * rate; } geeft total(80) de waarde 100 terug en total(80, 0.5) de waarde 120. Als je de parameters omdraait, is voor de gebruikelijke aanroep met het standaardtarief total(undefined, 80) nodig.

Oudere code kan level = level || 50; gebruiken. Dit vervangt ook 0, false en een lege string omdat het falsy-waarden zijn. Een parameter met een standaardwaarde behoudt die waarden: function setVolume(level = 50) { return level; } geeft 0 terug voor setVolume(0) en 50 voor setVolume(undefined).

Verzamel argumenten met rest
function sum(...numbers) {
  let total = 0;
  for (const n of numbers) {
    total += n;
  }
  return total;
}

sum(1, 2, 3) plaatst [1, 2, 3] in numbers en geeft 6 terug. sum() geeft die parameter een lege array, zodat de lus niets toevoegt en 0 teruggeeft. Een restparameter is een echte array, klaar voor arraymethoden of iteratie.

Vóór rest kan vaste invoer komen: in function log(label, ...values) { console.log(label, values); } geeft log("scores", 7, 9) aan label de string “scores” en aan values de array [7, 9]. Er is maar één restparameter toegestaan en die moet als laatste komen; anders kan JavaScript de resterende argumenten met deze syntaxis niet eenduidig toewijzen.

Pak argumenten uit met spread
Plaats van ...TaakVoorbeeld
Parameterlijst van de definitieResterende argumenten verzamelenfunction sum(...numbers) { ... }
Argumentenlijst van de aanroepArray-elementen uitpakkensum(...values)

Math.max(...[3, 7, 2]) ontvangt drie getallen en geeft 7 terug. Math.max([3, 7, 2]) ontvangt één array en geeft NaN terug. De drie punten zijn op de pagina identiek, maar de omringende syntaxis vertelt je welke taak ze uitvoeren.

Gewone functies hebben ook een arguments-object met de argumenten die eraan zijn doorgegeven. Het lijkt op een array, met items die een index hebben en een lengte, maar is geen echte array en heeft geen eigen methoden map of filter. Pijlfuncties hebben geen eigen arguments. Geef in nieuwe code die een flexibele lijst invoerwaarden nodig heeft de voorkeur aan een restparameter.

Belangrijkste punten

  • Standaardwaarden gelden voor ontbrekende argumenten en expliciete undefined, maar behouden 0 en null.
  • Een standaardexpressie wordt geëvalueerd voor elke aanroep die haar nodig heeft.
  • Eén restparameter verzamelt de resterende argumenten in een array en komt als laatste.
  • Spread pakt een array uit in afzonderlijke argumenten voor een aanroep.
  • Het oudere arguments-object lijkt op een array; rest levert een echte array op.

2.3 Geef resultaten terug vanuit een functie

Een teruggegeven waarde is de uitvoer die andere code van een aanroep ontvangt. Tonen kan dezelfde waarde op het scherm laten zien, maar geeft de aanroeper een ander resultaat tenzij de functie die waarde ook teruggeeft.

Gebruik de aanroep als waarde
function double(n) {
  return n * 2;
}
const x = double(5) + 1;

double(5) geeft 10 terug, dus wordt de toewijzing geëvalueerd als 10 plus 1 en wordt 11 opgeslagen. Een aanroep kan overal staan waar een geschikte waarde nodig is. double(double(3)) krijgt eerst 6 van de binnenste aanroep en geeft dan 12 terug van de buitenste. Math.round(double(2.3)) verdubbelt tot 4,6 en rondt af naar 5.

return beëindigt ook direct de huidige aanroep. Een bewakingsclausule handelt een speciaal geval af vóór het eigenlijke werk:

function safeDivide(a, b) {
  if (b === 0) {
    return null;
  }
  return a / b;
}

safeDivide(6, 0) geeft null terug en komt nooit bij de deling. safeDivide(6, 2) slaat de bewakingsclausule over en geeft 3 terug. Zet de voorwaarde vóór de bewerking die ze beschermt.

Onderscheid teruggeven van tonen
function addLog(a, b) {
  console.log(a + b);
}

addLog(2, 3) toont 5, maar de retourwaarde is undefined. Daardoor toont addLog(2, 3) * 2 de waarde 5 en wordt de expressie geëvalueerd tot NaN. Een functie die het einde bereikt zonder return of alleen return; uitvoert, geeft undefined terug. De weergave in de console is een neveneffect, niet de bruikbare numerieke uitvoer van de aanroep.

Als een aanroeper een som nodig heeft, schrijf je return a + b;. De aanroeper kan dan kiezen om die te tonen, op te slaan of in een andere berekening te gebruiken. Zo houd je beslissingen over de weergave buiten een herbruikbare berekening.

Houd de teruggegeven expressie op dezelfde regel
function brokenAdd(a, b) {
  return
  a + b;
}

JavaScript beëindigt de instructie return bij de regelafbreking. De functie geeft undefined terug; de latere expressie wordt nooit bereikt. Begin een lange expressie of open een rond haakje op de regel met return en ga eronder verder.

Verpak meerdere resultaten in één waarde

Een aanroep geeft één waarde terug, maar die waarde kan een array zijn:

function minMax(nums) {
  return [Math.min(...nums), Math.max(...nums)];
}
const [low, high] = minMax([4, 9, 1]);

De teruggegeven array is [1, 9]. Destructurering wijst het eerste item toe aan low en het tweede aan high. Er is nog steeds één teruggegeven waarde, met daarin twee bruikbare resultaten.

Een zuivere functie berekent haar uitvoer uit haar argumenten en verandert niets buiten zichzelf. double is zuiver. Tonen, een buitenste variabele bijwerken en een invoerarray wijzigen zijn neveneffecten. Zuivere berekeningen zijn gemakkelijk te controleren met voorbeelden van invoer en uitvoer; neveneffecten horen in duidelijk benoemde functies waar het programma zichtbare veranderingen nodig heeft.

Belangrijkste punten

  • return levert de waarde van de aanroep en beëindigt de huidige aanroep.
  • Als een functie alleen iets toont, blijft haar retourwaarde undefined.
  • Begin de teruggegeven expressie op de regel met return.
  • Eén teruggegeven array kan meerdere resultaten bevatten.
  • Zuivere functies zijn afhankelijk van hun argumenten en brengen geen veranderingen buiten zichzelf aan.

2.4 Volg functieaanroepen via de aanroepstapel

Wanneer een functie een andere aanroept, pauzeert de aanroeper totdat die aanroep terugkeert. De aanroepstapel houdt het onvoltooide werk bij, zodat de uitvoering op de juiste plaats kan worden hervat.

Voeg aanroepframes toe en verwijder ze

Elke actieve aanroep heeft een frame met de parameters, lokale variabelen en de plaats waar de uitvoering moet worden hervat. Een nieuwe aanroep komt boven op de stapel; een terugkeer verwijdert dat bovenste frame.

function square(n) {
  return n * n;
}
function sumOfSquares(a, b) {
  return square(a) + square(b);
}
sumOfSquares(3, 4);

Eerst begint sumOfSquares met a gelijk aan 3 en b gelijk aan 4. Die functie roept square(3) aan, dat 9 teruggeeft en eindigt. Daarna wordt square(4) uitgevoerd en geeft 16 terug. De gepauzeerde optelling kan nu worden voltooid als 9 plus 16 en sumOfSquares geeft 25 terug. De twee aanroepen van square overlappen elkaar in deze uitvoering niet.

Elke aanroep krijgt nieuwe parameters en lokale variabelen. Als je dezelfde functie twee keer aanroept, wordt de lokale numerieke toestand van een eerdere aanroep niet hergebruikt. Zelfs wanneer een functie zichzelf aanroept, heeft de nieuwe aanroep een eigen frame.

Maak een probleem kleiner met recursie

Een recursieve functie roept zichzelf aan. Een basisgeval eindigt zonder nog een aanroep van zichzelf; een recursief geval zet een stap in de richting van dat basisgeval.

function factorial(n) {
  if (n <= 1) {
    return 1;
  }
  return n * factorial(n - 1);
}

Voor niet-negatieve gehele getallen als invoer vermenigvuldigt dit de gehele getallen tot en met 1. Volg factorial(4) in twee richtingen:

  1. factorial(4) wacht op factorial(3).
  2. Die aanroep wacht op factorial(2).
  3. Die aanroep wacht op factorial(1).
  4. Het basisgeval geeft 1 terug.
  5. De wachtende aanroepen geven achtereenvolgens 2, 6 en 24 terug.

De vermenigvuldiging in de aanroep met n gelijk aan 4 gebeurt nadat de kleinere aanroep is teruggekeerd. De eigen n is tijdens het wachten 4 gebleven.

Een basisgeval moet bereikbaar zijn. Als je alleen n === 1 gebruikt, gaat het mis bij een begininvoer van 0 als elke recursieve aanroep 1 aftrekt: de waarden worden negatief en bereiken 1 nooit. n <= 1 vangt zowel 0 als 1 op. Zonder een pad dat de uitvoering stopt, putten herhaalde aanroepen de stapel uit. Chrome en Node.js melden “RangeError: Maximum call stack size exceeded”; Firefox gebruikt “InternalError: too much recursion”.

Herken een kleinere versie van dezelfde taak
function countItems(list) {
  let count = 0;
  for (const item of list) {
    if (Array.isArray(item)) {
      count += countItems(item);
    } else {
      count += 1;
    }
  }
  return count;
}

countItems([1, [2, 3], [4, [5]]]) geeft 5 terug. Elke geneste array stelt dezelfde telvraag over een kleinere lijst. Een lus is ook geschikt voor een eenvoudige faculteitsberekening; recursie is vooral nuttig wanneer de gegevens zelf genest zijn.

Als een aanroep mislukt, lees je het aanroepspoor vanaf de meest recente aanroep bovenaan. De volgende vermeldingen tonen welke onvoltooide aanroepen daartoe leidden. Herhaalde vermeldingen van één functie kunnen recursie onthullen die niet is gestopt.

Belangrijkste punten

  • De aanroepstapel houdt onvoltooide aanroepen bij; bij terugkeer wordt het meest recente frame verwijderd.
  • Elke aanroep heeft eigen parameters en lokale variabelen.
  • Recursie heeft een stopgeval nodig en moet daarnaartoe werken.
  • Recursieve resultaten worden in omgekeerde volgorde via de wachtende aanroepen teruggegeven.
  • Een aanroepspoor toont de mislukte aanroep en de aanroepen die daartoe leidden.
  • Geneste gegevens kunnen kleinere voorbeelden van dezelfde taak bevatten.
3

Leg uit waar je een variabele kunt gebruiken

Variabelenamen hebben betekenis binnen bereiken. Blokgrenzen, functiegrenzen en de plaats waar een functie is gedefinieerd bepalen welke declaraties de functie kan bereiken. Je volgt die grenzen om een waarde of fout te voorspellen en onderscheidt daarna overschaduwing van het bijwerken van een buitenste variabele. Hoisting en de tijdelijke dode zone verklaren waarom een naam al geregistreerd kan zijn voordat de uitvoering de bijbehorende regel bereikt, maar toch nog niet bruikbaar is.

3.1 Onderscheid blokbereik, functiebereik en globaal bereik

Het bereik van een variabele is het deel waarin de naam kan worden gebruikt. Dankzij bereik kunnen functies hun werkgegevens gescheiden houden en toch invoer en waarden uit omringende code gebruiken.

Trek grenzen rond declaraties

let en const hebben blokbereik. Een blok is een gebied tussen accolades, zoals een if-blok, een luslichaam of een functielichaam:

if (true) {
  const msg = "hi";
  console.log(msg);
}

Het tonen werkt binnen het blok. Als je erna console.log(msg); toevoegt, krijg je een ReferenceError omdat die buitenste code deze declaratie niet kan bereiken. Een andere buitenste declaratie met dezelfde naam zou een andere variabele zijn.

Parameters en variabelen binnen een functie zijn lokaal voor die functie. In function f() { let temp = 1; } kan code daarbuiten temp niet lezen. Twee functies kunnen elk een lokale total hebben zonder die te delen. Elke aanroep begint met nieuwe lokale variabelen; een teruggegeven geneste functie kan later via een closure toegang behouden.

Lees oudere declaraties met var
DeclaratieGrens
let of const binnen een blokDat blok
var binnen een functieDe omvattende functie, ook wanneer de declaratie in een binnenste blok staat
Declaratie op het hoogste niveau in een gewoon scriptHet globale bereik van het script
Declaratie op het hoogste niveau in een moduleDie module
function test() {
  if (true) {
    var x = 1;
  }
  return x;
}

test() geeft 1 terug omdat var de grens van if negeert. Als je dat vervangt door let x = 1;, mislukt het teruggeven: de x van het blok is daar niet beschikbaar. Zo houdt for (let i = 0; i < 3; i++) {} de variabele i ook binnen de lus, terwijl een var i na de lus beschikbaar blijft in de omvattende functie of het omvattende script en 3 bevat.

Kijk naar buiten vanaf de plaats waar de functie is geschreven

Bereiken zijn genest. Een binnenste functie kan namen in de omvattende bereiken gebruiken, maar buitenste code kan niet naar binnen zoeken in de lokale variabelen van een binnenste functie. Dit is lexicaal bereik: de plaats waar de code is geschreven, bepaalt welke namen beschikbaar zijn.

const level = "global";
function show() {
  return level;
}
function run() {
  const level = "local";
  return show();
}

run() geeft “global” terug. show is buiten run gedefinieerd, dus bevat het omvattende bereik de buitenste level. Als je de functie binnen run aanroept, krijgt die geen toegang tot de lokale level van die aanroeper.

Gebruik gedeelde toestand bewust

Een variabele op het hoogste niveau in een gewoon script is globaal en kan worden bereikt door functies binnen dat script. Gedeelde globale variabelen kunnen ervoor zorgen dat onafhankelijke taken elkaar beïnvloeden; scripts op dezelfde pagina kunnen ook botsen over namen. Door invoer door te geven en uitvoer terug te geven, houd je afhankelijkheden zichtbaar.

Declareer elke variabele. In strikte modus veroorzaakt count = 5; een ReferenceError als er geen bereikbare declaratie bestaat. Zonder strikte modus kan zo'n toewijzing per ongeluk een globale variabele maken. Een script kan strikte modus inschakelen met "use strict"; aan het begin; modules schakelen die automatisch in. Geef de voorkeur aan const voor waarden die niet opnieuw worden toegewezen en aan let wanneer hertoewijzing nodig is.

Belangrijkste punten

  • let en const volgen blokgrenzen; var volgt de grens van de omvattende functie.
  • Functieparameters en lokale variabelen zijn niet beschikbaar voor code daarbuiten.
  • Lexicaal bereik volgt waar een functie is gedefinieerd, niet waar die wordt aangeroepen.
  • Variabelen op het hoogste niveau van een module horen bij die module.
  • Declareer namen expliciet om onbedoelde globale toewijzingen te voorkomen.

3.2 Voorspel naar welke variabele een naam verwijst

Dezelfde naam kan in meerdere bereiken voorkomen. JavaScript vindt de relevante declaratie door vanaf de huidige code naar buiten te zoeken en bij de eerste overeenkomst te stoppen.

Volg de bereikketen
let x = 1;
function f() {
  let x = 2;
  return x;
}

f() geeft 2 terug. De lokale declaratie overschaduwt de buitenste x, dus stopt het zoeken binnen f. De buitenste waarde blijft 1. Een parameter kan op dezelfde manier een naam overschaduwen. Als geen enkel bereik in de keten een naam declareert, veroorzaakt het lezen ervan een ReferenceError.

Een toewijzing declareert geen nieuwe variabele. Bij let count = 0; function add() { count = count + 1; } vindt add de buitenste declaratie en wijzigt de variabele. Als je let toevoegt, verandert de betekenis: je maakt een nieuwe lokale naam die juist de waarde kan verbergen die je wilde lezen.

Onderscheid registratie van initialisatie

Hoisting beschrijft hoe declaraties worden geregistreerd voordat hun bereik wordt uitgevoerd. Hun gedrag aan het begin verschilt:

DeclaratieVóór de initialisatieregel
FunctiedeclaratieDe functie is beschikbaar
varDe waarde is undefined
let of constToegang veroorzaakt een ReferenceError

Zo toont console.log(a); var a = 5; de waarde undefined. De toewijzing van 5 heeft nog niet plaatsgevonden. console.log(b); let b = 5; mislukt daarentegen. De periode waarin de lexicale naam bestaat maar niet toegankelijk is, heet de tijdelijke dode zone, vaak afgekort tot TDZ.

Volg overschaduwing vóór een declaratieregel
let n = 10;
function f() {
  console.log(n);
  let n = 20;
}
f();

De binnenste n overschaduwt de buitenste in het hele functielichaam, ook vóór de regel waar de declaratie is geschreven. Bij console.log(n) staat die binnenste naam nog in de TDZ, dus veroorzaakt de aanroep een ReferenceError. JavaScript slaat een niet-geïnitialiseerde lokale declaratie niet over om terug te vallen op de buitenste waarde 10.

Hetzelfde probleem doet zich voor bij let count = count + 1; binnen add. De rechterkant leest de nieuwe lokale count voordat die is geïnitialiseerd. Als het de bedoeling is een buitenste teller bij te werken, gebruik dan een toewijzing zonder nieuwe declaratie. Als het de bedoeling is een afzonderlijke waarde te berekenen, geef die dan een andere naam en lees de buitenste teller expliciet.

Onderscheid hertoewijzing van mutatie

Met let en const kun je dezelfde naam niet opnieuw declareren in één bereik; dat veroorzaakt een SyntaxError. Een binnenste bereik mag een eigen naam declareren: dat is overschaduwing. var staat herhaalde declaraties in hetzelfde bereik toe, waardoor onbedoeld hergebruik van een naam moeilijker opvalt.

const verhindert hertoewijzing van de variabele. Het bevriest een array niet:

const list = [];
list.push(1);

De referentie die in list is opgeslagen blijft dezelfde, terwijl de array verandert in [1]. Met list = []; zou je proberen de opgeslagen referentie te vervangen en dat zou mislukken.

Houd een declaratie in het kleinste bereik dat die nodig heeft. Verschillende namen voor verschillende taken verminderen de noodzaak om overschaduwing in gedachten bij te houden. Als je vóór gebruik initialiseert, voorkom je fouten door de TDZ.

Belangrijkste punten

  • Bij het opzoeken van een naam stopt JavaScript bij de dichtstbijzijnde declaratie in het huidige of een omvattend bereik.
  • Een lokale declaratie overschaduwt een buitenste naam ook al vóór de initialisatie.
  • var begint als undefined; let en const zijn niet toegankelijk in hun TDZ.
  • Een toewijzing werkt een bestaande binding bij; een declaratie maakt er een.
  • const voorkomt hertoewijzing, terwijl de inhoud van een array nog kan veranderen.
  • Een herhaalde declaratie in één bereik verschilt van overschaduwing in een genest bereik.
4

Gebruik closures om functies een eigen geheugen te geven

Een teruggegeven functie kan toegang houden tot de variabelen rond haar definitie. Die blijvende verbinding geeft een teller geheugen en laat een fabriek functies met eigen instellingen maken. Je volgt afzonderlijke fabrieksaanroepen, gedeelde toestand en latere wijzigingen aan vastgelegde variabelen. Daarna gebruik je dezelfde regels om functies uit te leggen die in een lus zijn gemaakt. Privétoestand volgt uit gewoon lexicaal bereik, ook nadat de buitenste aanroep is teruggekeerd.

4.1 Leg uit wat een closure onthoudt

Een functie houdt een koppeling met het bereik waarin die is gemaakt. De functie en de behouden toegang vormen een closure. Die koppeling is vooral nuttig wanneer een geneste functie wordt teruggegeven en aangeroepen nadat de buitenste aanroep is beëindigd.

Geef een teruggegeven functie geheugen
function makeCounter() {
  let count = 0;
  return function () {
    count = count + 1;
    return count;
  };
}
const counter = makeCounter();

De aanroep van makeCounter maakt count, maakt een binnenste functie en geeft die functie terug. Het binnenste functielichaam wordt nog niet uitgevoerd. counter bevat nu de functiewaarde. De eerste aanroep verandert de behouden count van 0 in 1 en geeft 1 terug. De volgende aanroep verandert dezelfde variabele in 2 en geeft 2 terug.

Het stapelframe van de buitenste aanroep is beëindigd, maar de vastgelegde variabele blijft toegankelijk. Een lokale variabele die nergens meer bereikbaar wordt gebruikt, kan worden vrijgegeven; hier heeft de aanroepbare binnenste functie die nog nodig. Toegang via een closure blijft na terugkeer bestaan zonder de variabele globaal te maken.

Maak onafhankelijk geheugen met afzonderlijke aanroepen
const a = makeCounter();
const b = makeCounter();
a();
a();
b();

De resultaten zijn 1, 2 en 1. Elke fabrieksaanroep heeft een andere count gemaakt. De twee functies die uit afzonderlijke aanroepen zijn teruggegeven, hebben dezelfde code maar verschillende behouden omgevingen.

Het kopiëren van een teruggegeven functiereferentie werkt anders. Bij const alias = a; gebruikt alias() de bestaande teller van a; de aanroep roept makeCounter niet aan en maakt geen nieuwe omgeving.

Bewaar variabelen, geen momentopnamen
let greeting = "Hi";
const say = () => greeting;
greeting = "Hello";

say() geeft “Hello” terug. De closure leest de variabele wanneer die wordt uitgevoerd, dus is een latere wijziging zichtbaar. De closure slaat geen vaststaande kopie van “Hi” op bij het maken.

Code daarbuiten kan de lokale count niet direct bereiken en counter.count is undefined. Alleen code met toegang tot die lexicale omgeving kan de variabele lezen of bijwerken. Als je de teller vanuit een andere functie aanroept, verandert dat niet welke tellerwaarde wordt gebruikt.

Deel toestand binnen één buitenste aanroep
function makeWallet() {
  let balance = 0;
  return [
    function deposit(n) { balance += n; return balance; },
    function getBalance() { return balance; }
  ];
}
const [deposit, getBalance] = makeWallet();
deposit(50);
deposit(20);

getBalance() geeft 70 terug omdat beide teruggegeven functies in dezelfde aanroep zijn gemaakt en naar dezelfde balance verwijzen. Een andere aanroep van makeWallet() maakt een afzonderlijk saldo.

Belangrijkste punten

  • Een closure behoudt toegang tot het bereik waarin haar functie is gemaakt.
  • Een vastgelegde variabele kan bruikbaar blijven nadat de buitenste aanroep is teruggekeerd.
  • Afzonderlijke fabrieksaanroepen maken afzonderlijke omgevingen.
  • Closures lezen de huidige waarden van variabelen, geen momentopnamen van toen ze werden gemaakt.
  • Functies uit dezelfde buitenste aanroep kunnen privétoestand delen.

4.2 Gebruik closures voor functiefabrieken en privétoestand

Een functiefabriek gebruikt toegang via een closure om functies met eigen instellingen of toestand te maken. De aanroeper geeft de configuratie één keer door en gebruikt de teruggegeven functie daarna vaak.

Stel een functie in met een parameter
function makeMultiplier(factor) {
  return (n) => n * factor;
}
const double = makeMultiplier(2);
const triple = makeMultiplier(3);

double(5) geeft 10 terug en triple(5) geeft 15 terug. Elke teruggegeven pijlfunctie behoudt de factor van haar eigen fabrieksaanroep. De buitenste functie stelt het gedrag in; de binnenste voert het herhaalde werk uit.

De compacte vorm is const makeMultiplier = (factor) => (n) => n * factor;. Twee pijlen betekenen dat twee functies worden gemaakt, niet dat twee opeenvolgende berekeningen op één getal worden uitgevoerd. makeMultiplier(4)(5) geeft eerst een functie terug die met 4 is ingesteld en roept die daarna aan met 5 om 20 te krijgen.

Handhaaf een regel voor privétoestand
function makeLimiter(max) {
  let used = 0;
  return function () {
    if (used >= max) {
      return false;
    }
    used = used + 1;
    return true;
  };
}
const tryLogin = makeLimiter(3);

De eerste drie aanroepen geven true terug en verhogen used. De vierde geeft false terug vóór de verhoging. used is lokaal voor de fabrieksaanroep, dus code daarbuiten kan de variabele niet via die naam terugzetten. De teruggegeven functie bepaalt welke wijzigingen mogelijk zijn. Een andere begrenzer zou een eigen variabele used en een eigen maximum hebben.

Onderzoek functies die in lussen zijn gemaakt
const fns = [];
for (var i = 0; i < 3; i++) {
  fns.push(() => i);
}

De lus maakt drie functies maar slechts één var i. Na de lus bevat die variabele 3. Als je nu een van de opgeslagen functies aanroept, geeft die 3 terug omdat elke closure dezelfde huidige binding leest. Een functie maken evalueert haar functielichaam niet en legt de huidige i niet als momentopname vast.

Als je de kop verandert in let i = 0, krijgt de lus voor elke iteratie een afzonderlijke binding. De opgeslagen functies geven dan 0, 1 en 2 terug. Hetzelfde verschil verklaart uitgesteld tonen: een setTimeout-callback die na de lus var i leest, ziet de eindwaarde, terwijl de versie met let de waarde van elke iteratie behoudt.

Herken een direct aangeroepen expressie

Oudere code maakt vaak een privéfunctiebereik en voert de functie direct uit:

(function () {
  var hidden = 1;
  console.log(hidden);
})();

Dit is een direct aangeroepen functie-expressie, of IIFE. De buitenste ronde haakjes maken er een functie-expressie van; de laatste ronde haakjes roepen die aan. hidden hoort bij die functie en blijft daardoor buiten het omringende globale bereik. Het is een veelvoorkomend patroon in code van vóór declaraties met blokbereik en modules.

Behoud van toegang heeft ook invloed op het geheugen. Een aanroepbare closure die een grote array nodig heeft, houdt die gegevens bereikbaar. Wanneer de functie en de vastgelegde gegevens niet meer bereikbaar zijn, kunnen ze worden vrijgegeven. Sla lang bestaande closures bewust op wanneer hun geheugengebruik deel uitmaakt van de taak.

Belangrijkste punten

  • Fabrieken geven functies terug die door hun argumenten zijn ingesteld.
  • Privévariabelen kunnen via de teruggegeven bewerkingen worden gewijzigd.
  • Closures in een lus met var delen één binding; lusiteraties met let krijgen afzonderlijke bindingen.
  • Een IIFE maakt een functiebereik en voert de functie direct uit.
  • Bereikbare closures houden de vastgelegde gegevens die ze nodig hebben bereikbaar.
5

Geef functies door aan andere functies

Door een functie door te geven kan een aanroeper een deel van het gedrag van een andere functie kiezen. Je onderzoekt hoe ontvangende functies callbacks aanroepen, welke argumenten ze meegeven en hoe ze het resultaat gebruiken. Bekende arraymethoden worden vervolgens voorbeelden van herbruikbare patronen met hogere-ordefuncties. Ten slotte omhullen teruggegeven functies aanroepen, verbinden ze uitvoer met invoer of houden ze geselecteerde argumenten klaar voor later gebruik. Zo combineren ze functiewaarden met toegang via closures.

5.1 Geef een callback door aan een functie

Een callback is een functie die als argument wordt meegegeven zodat een andere functie die kan aanroepen. Zo kan de ontvangende functie de volledige taak afhandelen terwijl de aanroeper een specifieke handeling of test levert.

Geef een handeling door aan een lus
function repeat(times, action) {
  for (let i = 0; i < times; i++) {
    action(i);
  }
}
repeat(3, (i) => console.log(i));

repeat beheert de lus en kiest de waarden 0, 1 en 2. De pijlfunctie bepaalt wat er met elke waarde gebeurt: die wordt getoond. Elke action(i) roept de meegegeven functie aan met het nummer van die iteratie.

Je kunt een bestaande functie doorgeven of er direct op die plek een schrijven. repeat(2, sayHi) geeft de benoemde functie door. repeat(2, (i) => console.log("Round " + (i + 1))) toont “Round 1” en “Round 2”. Een callback mag argumenten negeren die niet nodig zijn.

Geef de waarde door, roep de functie niet te vroeg aan

repeat(3, sayHi()) evalueert sayHi() tijdens het voorbereiden van de argumenten. Als sayHi alleen iets toont, is de retourwaarde undefined, dus ontvangt repeat die waarde als action. De latere action(i) mislukt met een TypeError omdat undefined niet aanroepbaar is.

Gebruik repeat(3, sayHi) om de functie door te geven. Als de uiteindelijke aanroep gekozen argumenten nodig heeft, geef dan een omhullende functie door zoals () => sayHi(), zodat de aanroep binnen het functielichaam van de callback plaatsvindt. Een functie maken en een functie aanroepen zijn afzonderlijke stappen.

Controleer welke argumenten de ontvanger levert

Arraycallbacks ontvangen vaak meer dan één argument: het element, de index en de hele array. Een bestaande functie doorgeven is alleen veilig wanneer die invoer past bij de betekenis van haar parameters.

["1", "2", "3"].map(parseInt);

Dit geeft [1, NaN, NaN] terug. parseInt accepteert een tweede argument voor het grondtal, dus verandert de array-index het gedrag. Gebruik ["1", "2", "3"].map((s) => parseInt(s, 10)) om grondtal 10 expliciet te kiezen, of .map(Number) om deze strings te converteren.

Geef een antwoord terug aan de ontvanger
function countIf(arr, test) {
  let n = 0;
  for (const x of arr) {
    if (test(x)) {
      n++;
    }
  }
  return n;
}

countIf([3, 8, 12, 5], (x) => x > 4) geeft 3 terug. De callback beantwoordt voor elk item een vraag; countIf gebruikt elk antwoord om te bepalen of de teller wordt verhoogd. Vergelijk dit met repeat, waarvan de lus de retourwaarde van de callback negeert. De code of documentatie van de ontvangende functie vertelt je zowel welke argumenten worden doorgegeven als wat de rol van het resultaat is.

Callbacks kunnen direct of later worden uitgevoerd. repeat en arraymethoden roepen ze synchroon aan voordat ze terugkeren. setTimeout(sayHi, 2000) plant er een voor later, terwijl de daaropvolgende code direct doorgaat. De term callback beschrijft hoe een functie wordt meegegeven, niet wanneer die moet worden uitgevoerd.

Belangrijkste punten

  • Een callback is een functie die wordt doorgegeven zodat een andere functie die kan aanroepen.
  • De ontvanger bepaalt de argumenten van de callback en of het resultaat wordt gebruikt.
  • Als je te vroeg haakjes voor een aanroep toevoegt, geef je mogelijk een resultaat door in plaats van een functie.
  • Argumenten van een arraycallback kunnen het gedrag van een bestaande functie veranderen.
  • Callbacks kunnen synchroon of uitgesteld zijn.

5.2 Gebruik en schrijf hogere-ordefuncties

Een hogere-ordefunctie accepteert een functie, geeft een functie terug of doet beide. De functiewaarde levert gedrag, terwijl de hogere-ordefunctie een herbruikbaar patroon beheert.

Schrijf het patroon één keer
function myMap(arr, transform) {
  const result = [];
  for (const item of arr) {
    result.push(transform(item));
  }
  return result;
}

myMap([1, 2, 3], (n) => n * n) geeft [1, 4, 9] terug. De lus en de opbouw van de uitvoerarray blijven hetzelfde; de callback bepaalt hoe elk item verandert. Een bijpassend filter voegt een item alleen toe wanneer test(item) truthy is. Met [4, 7, 10, 3] en (n) => n % 2 === 0 behoudt dat patroon [4, 10].

Kies de afspraken voor de callback die je nodig hebt
MethodeTaak van de callbackResultaat van de methode
mapElke getransformeerde waarde teruggevenEen nieuwe array van dezelfde lengte
filterEen truthy-waarde teruggeven voor items die behouden moeten blijvenEen nieuwe array met geselecteerde items
findTesten op een passend itemEerste overeenkomst, of undefined
forEachVoor elk item een handeling uitvoerenundefined
reduceDe volgende accumulator teruggevenDe uiteindelijke accumulator

map, filter en find wijzigen zelf de invoerarray niet, maar callbacks kunnen die nog steeds veranderen. Als een methode een nieuwe array teruggeeft, maakt dat niet elke meegegeven callback zuiver.

Geef een resultaat door tijdens een reductie
[5, 10, 15].reduce((total, n) => total + n, 0);

De beginwaarde van de accumulator is 0. De callback geeft 5 terug voor het eerste item, 15 voor het tweede en 30 voor het derde. Elke retourwaarde wordt de total van de volgende aanroep. De methode geeft na het laatste item 30 terug. Bij een lege array zonder beginwaarde voor de accumulator veroorzaakt reduce een TypeError; een expliciete beginwaarde bepaalt ook het bruikbare resultaat voor lege invoer.

Omdat methoden arrays teruggeven, kun je ze aaneenschakelen. [3, 8, 12, 5].filter((n) => n > 4).map((n) => n * 2) behoudt eerst [8, 12, 5] en transformeert dat daarna in [16, 24, 10]. Lees de keten van links naar rechts in de uitvoeringsvolgorde.

Geef een numerieke sorteerregel op

Zonder vergelijkingsfunctie vergelijkt sort items als strings. [10, 9, 1].sort() levert daarom [1, 10, 9] op. Gebruik voor oplopende numerieke volgorde .sort((a, b) => a - b). Een negatieve retourwaarde zet a eerst, een positieve zet b eerst en nul maakt het paar gelijkwaardig voor de ordening. Anders dan map en filter verandert sort de volgorde in de invoerarray.

Controleer de retourwaarden

[1, 2, 3].map((n) => { n * 2; }) levert [undefined, undefined, undefined] op omdat het blok geen return heeft. Als je forEach gebruikt om via een toewijzing een nieuw resultaat op te bouwen, gaat dat ook mis wanneer je verwacht dat de methode zelf een array teruggeeft. Kies map voor transformatie en forEach voor handelingen waarvan de verzamelde uitvoer niet nodig is.

Een hogere-ordemethode maakt een bekend patroon duidelijk. Een gewone lus blijft nuttig wanneer het werk break nodig heeft of niet past bij de afspraken van de methode.

Belangrijkste punten

  • Hogere-ordefuncties accepteren functies, geven functies terug of doen beide.
  • map, filter en find gebruiken resultaten van callbacks op verschillende manieren.
  • forEach geeft undefined terug; reduce geeft de uiteindelijke accumulator terug.
  • Een reductiecallback moet de volgende accumulator teruggeven.
  • Numeriek sorteren heeft een vergelijkingsfunctie nodig en wijzigt de oorspronkelijke array.
  • Een methode die een nieuwe array teruggeeft, kan nog steeds callbacks met neveneffecten uitvoeren.

5.3 Bouw nieuwe functies op uit bestaande functies

Een functie kan een nieuwe functie teruggeven die een bestaande functie onthoudt. Omhullende functies, functiecompositie en partiële toepassing gebruiken dit patroon om gedrag aan te passen zonder het functielichaam van de oorspronkelijke functie te kopiëren.

Omhul een aanroep en behoud het resultaat
function logged(fn) {
  return (...args) => {
    console.log("Calling with", args);
    const result = fn(...args);
    console.log("Result", result);
    return result;
  };
}
const add = (a, b) => a + b;

logged(add) maakt een functie die add als fn behoudt. De aanroep logged(add)(2, 3) verzamelt de argumenten, geeft ze door aan add, toont de teruggegeven waarde en geeft 5 terug. Rest verzamelt de invoer van de omhullende functie; spread geeft die door. De laatste return houdt de uitvoer beschikbaar voor latere berekeningen.

logged(add(2, 3)) geeft daarentegen het getal 5 door. Als je die omhullende functie later aanroept, probeert die 5 aan te roepen en krijg je een TypeError. Er zijn twee stappen: stel de omhullende functie in met een functie en roep daarna de teruggegeven functie aan met invoer.

Behoud toestand rond een bewerking
function once(fn) {
  let done = false;
  let result;
  return (...args) => {
    if (!done) {
      done = true;
      result = fn(...args);
    }
    return result;
  };
}

Voor een bewerking die normaal terugkeert, voert de eerste aanroep fn uit en slaat het resultaat op. Latere aanroepen geven die opgeslagen waarde terug zonder fn opnieuw uit te voeren, zelfs als hun argumenten verschillen. De booleaanse waarde houdt bij of de bewerking is uitgevoerd; controleren of het resultaat truthy is, zou verkeerd zijn wanneer een geldig resultaat 0 of false is. Elke aanroep van once maakt een eigen vlag en opgeslagen resultaat.

Geef een resultaat door aan een andere functie
const compose = (f, g) => (x) => f(g(x));
const addOne = (n) => n + 1;
const square = (n) => n * n;

compose(square, addOne)(3) voert eerst addOne(3) uit en kwadrateert daarna 4 om 16 terug te geven. compose(addOne, square)(3) kwadrateert eerst 3 en telt er daarna 1 bij op, wat 10 teruggeeft. De functie die het dichtst bij de invoer staat, wordt eerst uitgevoerd, dus is de volgorde van de argumenten voor compose van belang.

Leg enkele argumenten vooraf vast
function partial(fn, ...fixed) {
  return (...rest) => fn(...fixed, ...rest);
}
const greetWith = (greeting, name) => greeting + ", " + name;
const hello = partial(greetWith, "Hello");

hello("Ana") roept greetWith("Hello", "Ana") aan en geeft “Hello, Ana” terug. Deze hulpfunctie voor partiële toepassing zet vaste argumenten eerst en latere argumenten daarna; als je die volgorde verandert, verandert de onderliggende aanroep.

Belangrijkste punten

  • Een omhullende functie behoudt een functie en voegt gedrag toe rond de aanroep ervan.
  • Met rest en spread kan een omhullende functie afzonderlijke argumenten doorgeven.
  • Door het resultaat van de omhulde functie terug te geven, blijft het bruikbaar voor de aanroeper.
  • Een omhullende functie voor eenmalige uitvoering behoudt zowel een vlag als het eerste resultaat.
  • compose(f, g) past g toe vóór f.
  • Partiële toepassing legt geselecteerde argumenten vast vóór latere aanroepen.

JavaScript-functies: voorbeelden

5 Walkthroughs

1

Maak een functie, sla die op en roep die aan

11 stappen
Volg een herbruikbare begroeting via declaraties, functiewaarden en functielichamen van pijlfuncties.
  1. 1
    IntroductieOnderscheid het recept van de aanroep

    Een functie slaat instructies op zodat meerdere aanroepen ze kunnen hergebruiken. De definitie beschrijft een taak; een aanroep voert die taak uit met bepaalde invoer.

    Volg een begroeting in drie vormen: een declaratie, een expressie die in een variabele is opgeslagen en een pijlfunctie. Let op twee details terwijl de syntaxis verandert: wanneer de functie beschikbaar wordt en of haar functielichaam een waarde teruggeeft.

  2. 2
    VoorbeeldDefinieer een begroeting
    function greet(name) {
      console.log("Hello, " + name + "!");
    }
    

    Het sleutelwoord, de naam, de parameterlijst en het functielichaam vormen een declaratie. Er is nog niets getoond: de definitie slaat de instructies op.

    name is een parameter waarvan de waarde uit een aanroep zal komen. Het functielichaam is herbruikbaar omdat het beschrijft hoe de begroeting wordt opgebouwd zonder vooraf de naam van één persoon te kiezen.

  3. 3
    VoorbeeldVoer de opgeslagen instructies uit
    greet("Amira");
    greet("Li");
    

    De aanroepen tonen “Hello, Amira!” en “Hello, Li!” op afzonderlijke regels. Elke aanroep begint hetzelfde functielichaam opnieuw met eigen invoer.

    De expressie greet alleen is de functiewaarde. De ronde haakjes in greet("Li") vragen om uitvoering. Ook een functie zonder invoer heeft bij een aanroep ronde haakjes nodig, zoals in sayHi().

  4. 4
    UitdagingVoorspel wat de vroege aanroep doet

    Wat wordt getoond wanneer dit script wordt uitgevoerd?

    show();
    function show() { console.log("Ready"); }
    

    ---reveal---

    Het script toont één keer “Ready”. Op de declaratie wordt binnen haar bereik hoisting toegepast, dus is de functie op de eerste regel beschikbaar. Hoisting voert het functielichaam niet zelf uit: dat doet de expliciete aanroep show(). Een regel met alleen show; zou de functie lezen zonder iets te tonen.

  5. 5
    UitlegBewaar de functie als waarde
    const square = function (n) {
      return n * n;
    };
    const alias = square;
    

    De expressie maakt een functie en square slaat die op. De tweede toewijzing kopieert de referentie naar alias; er wordt geen kwadraat berekend. Zowel square(3) als alias(3) geeft 9 terug.

    Ter vergelijking: const answer = square(3); roept de functie aan en slaat het teruggegeven getal op.

  6. 6
    UitdagingZoek waar het eerst misgaat

    Toont dit script 16?

    console.log(square(4));
    const square = function (n) { return n * n; };
    

    ---reveal---

    Nee. Als je square leest vóór de initialisatie met const, krijg je een ReferenceError. De toewijzing is nog niet uitgevoerd, dus is de functiewaarde van de expressie niet beschikbaar. Verplaats de aanroep naar onder de toewijzing of gebruik een functiedeclaratie als de functie eerder in dit bereik aanroepbaar moet zijn.

  7. 7
    VoorbeeldGebruik een pijlfunctie met een expressie
    const square = (n) => n * n;
    const add = (a, b) => a + b;
    

    Een expressie als functielichaam van een pijlfunctie geeft haar waarde terug, dus geeft square(4) de waarde 16 terug en add(2, 3) de waarde 5.

    Bij één eenvoudige parameter mogen de ronde haakjes weg: n => n * n. Lege lijsten, meerdere parameters, parameters met standaardwaarden en restparameters hebben ze nodig. Pijlfuncties zijn expressies, dus moeten deze const-variabelen nog steeds vóór gebruik worden geïnitialiseerd.

  8. 8
    UitdagingHerstel een ontbrekend resultaat

    Waarom geeft add(2, 3) de waarde undefined terug en welke wijziging zorgt ervoor dat de functie 5 teruggeeft?

    const add = (a, b) => { a + b; };
    

    ---reveal---

    De accolades beginnen een blok, dus wordt de expressie geëvalueerd maar niet teruggegeven. Schrijf (a, b) => { return a + b; } of verwijder de accolades en gebruik (a, b) => a + b. Beide oplossingen geven de som terug. Alleen een puntkomma na de toewijzing toevoegen verandert niet wat het functielichaam teruggeeft.

  9. 9
    TipGeef een objectexpressie terug
    const makePoint = (x, y) => ({ x: x, y: y });
    

    De ronde haakjes maken van de objectliteral een expressie die door het functielichaam wordt teruggegeven. Een openingsaccolade zonder ronde haakjes eromheen zou daarentegen een blok beginnen.

    Pijlfuncties hebben geen eigen this of arguments en kunnen geen constructor zijn. De korte vorm werkt goed voor eenvoudige berekeningen, maar deze verschillen zijn van belang wanneer je andere soorten functies omzet.

  10. 10
    UitdagingVolg een functie en haar alias

    Wat geeft copy(5) terug?

    const adjust = (n) => { return n + 2; };
    const copy = adjust;
    

    ---reveal---

    De aanroep geeft 7 terug. Het blok van de pijlfunctie bevat een expliciete return en copy bevat dezelfde aanroepbare functie als adjust. De toewijzing heeft de functie niet aangeroepen of een numeriek resultaat opgeslagen. Als je const copy = adjust; zou vervangen door const copy = adjust(5);, zou je 7 opslaan en dat is niet aanroepbaar.

  11. 11
    SamenvattingLees welke bewerking elke regel uitvoert

    Een declaratie maakt een benoemde taak die vroeg in haar bereik beschikbaar is. Een expressie maakt een functiewaarde wanneer de uitvoering die bereikt. Een expressie als functielichaam van een pijlfunctie geeft automatisch een waarde terug; een instructieblok als functielichaam heeft return nodig.

    Onderscheid bij het volgen van code een functiedefinitie, een referentietoewijzing en een aanroep. Dat zijn verschillende bewerkingen, ook als ze dezelfde naam gebruiken.

2

Volg invoer, uitvoer en wachtende aanroepen

16 stappen
Koppel argumenten, volg retourwaarden en werk een korte recursieve berekening terug af.

Sla deze les op om elke Walkthrough stap voor stap te volgen.

  1. 1
    IntroductieVolg wat een aanroep ontvangt en teruggeeft
  2. 2
    VoorbeeldKoppel argumenten op positie
  3. 3
    VoorbeeldOnderscheid mutatie van hertoewijzing
  4. 4
    UitdagingBehoud de oorspronkelijke invoer
  5. 5
    UitlegEen standaardwaarde geldt bij undefined
  6. 6
    VoorbeeldVerzamel en pak daarna uit
  7. 7
    UitdagingGebruik een standaardwaarde met rest
  8. 8
    VoorbeeldGeef het getal terug dat de aanroeper nodig heeft
  9. 9
    VoorbeeldStop een uitvoeringspad door voortijdig terug te keren
  10. 10
    UitdagingEvalueer van binnen naar buiten
  11. 11
    VoorbeeldOnthoud de onvoltooide aanroeper
  12. 12
    UitlegGeef recursie een stoppad
  13. 13
    VoorbeeldWerk de wachtende vermenigvuldigingen terug af
  14. 14
    UitdagingHerstel een recursieve grens
  15. 15
    VerbandLees een fout via de stapel
  16. 16
    SamenvattingVolg een waarde door elke grens
3

Zoek de declaratie achter een naam

10 stappen
Volg blokgrenzen, lexicaal zoeken en het moment van initialisatie.

Sla deze les op om elke Walkthrough stap voor stap te volgen.

  1. 1
    IntroductieVraag je af waar de naam hoort
  2. 2
    VoorbeeldVergelijk blok- en functiegrenzen
  3. 3
    VoorbeeldGebruik de plaats van de definitie
  4. 4
    UitdagingVolg een lokale en een buitenste waarde
  5. 5
    UitlegStop bij de dichtstbijzijnde declaratie
  6. 6
    KernpuntGeregistreerd is niet hetzelfde als geïnitialiseerd
  7. 7
    UitdagingVoorspel wat er gebeurt bij het lezen van een overschaduwde naam
  8. 8
    TipHoud hertoewijzing en mutatie uit elkaar
  9. 9
    UitdagingCombineer een callback met het moment van opzoeken
  10. 10
    SamenvattingVolg eerst de plaats en dan de waarde
4

Geef teruggegeven functies een eigen geheugen

11 stappen
Volg gedeelde en onafhankelijke toestand in closures en bekijk daarna functies die binnen een lus zijn gemaakt.

Sla deze les op om elke Walkthrough stap voor stap te volgen.

  1. 1
    IntroductieBehoud toegang na een return
  2. 2
    VoorbeeldMaak een teller zonder die aan te roepen
  3. 3
    VoorbeeldWerk de behouden variabele bij
  4. 4
    UitdagingVergelijk onafhankelijke tellers
  5. 5
    KernpuntBehoud de binding, geen momentopname
  6. 6
    VoorbeeldMaak een ingestelde berekening
  7. 7
    VoorbeeldHoud een gebruiksteller privé
  8. 8
    UitdagingVerklaar drie gelijke resultaten
  9. 9
    VerbandHerken privébereik in oudere code
  10. 10
    UitdagingDeel één ingestelde bewerking
  11. 11
    SamenvattingVolg hoeveel omgevingen er bestaan
5

Geef gedrag door en bouw aangepaste functies

15 stappen
Volg callbackargumenten, resultaten van arraymethoden en functies die ingestelde functies teruggeven.

Sla deze les op om elke Walkthrough stap voor stap te volgen.

  1. 1
    IntroductieLaat een functie het veranderende gedrag leveren
  2. 2
    VoorbeeldRoep de meegegeven handeling aan
  3. 3
    UitdagingGebruik een callbackresultaat
  4. 4
    TipBekijk alle callbackargumenten
  5. 5
    VoorbeeldSchrijf een transformatiepatroon
  6. 6
    UitlegKies de vorm van het resultaat
  7. 7
    UitdagingVolg een selectie en een transformatie
  8. 8
    KernpuntKies de numerieke volgorde bewust
  9. 9
    VoorbeeldOmhul een aanroep en geef die door
  10. 10
    UitlegOnthoud of een aanroep is uitgevoerd
  11. 11
    VoorbeeldCombineer functies van binnen naar buiten
  12. 12
    VoorbeeldLeg invoer vast vóór de latere aanroep
  13. 13
    UitdagingGeef een ingestelde callback door
  14. 14
    UitdagingHerstel een verloren resultaat van een omhullende functie
  15. 15
    SamenvattingControleer beide stappen van code met hogere-ordefuncties

JavaScript-functies: oefenvragen

50 Oefenvragen in 5 sets

Set 1: Kies invoer en volg behouden toestand10 Oefenvragen

Vraag 1 van 10

Wat gebeurt er wanneer dit script wordt uitgevoerd?

announce();
function announce() { console.log("Open"); }
  1. Het script veroorzaakt een ReferenceError.
  2. Het script toont één keer undefined.
  3. Het script toont één keer “Open”.
  4. Het script veroorzaakt een TypeError.
Toon antwoordVerberg antwoord
Antwoord: C
Op de declaratie wordt binnen het bereik van het script hoisting toegepast, dus is announce al een functie wanneer de eerste regel die aanroept. Het functielichaam toont één keer “Open”. Het moment van initialisatie van een functie-expressie die in const is opgeslagen zou anders zijn, maar deze code gebruikt een declaratie.

Vraag 2 van 10

Hoe kan een pijlfunctie een object teruggeven met een eigenschap value die gelijk is aan de invoer n?
  1. (n) => ({ value: n })
  2. (n) => { return; value: n; }
  3. (n) => (value = n)
  4. (n) => { value: n }
Toon antwoordVerberg antwoord
Antwoord: A
De ronde haakjes maken van { value: n } een objectexpressie, die de expressie als functielichaam van de pijlfunctie teruggeeft. Zonder die ronde haakjes beginnen de accolades een blok en wordt value: n gelezen als een instructie met een label, zodat geen object wordt teruggegeven. Een return; zonder waarde geeft ook undefined terug.

Vraag 3 van 10

Wat geeft de aanroep terug?

function combine(first, ...rest) {
  return first + rest.length;
}
const values = [8, 2, 6];
combine(...values);
  1. 16
  2. 8
  3. 11
  4. 10
Toon antwoordVerberg antwoord
Antwoord: D
Spread geeft drie afzonderlijke argumenten door. De vaste parameter krijgt 8 en rest verzamelt [2, 6], met lengte 2, dus geeft de functie 10 terug. Als je alle drie de waarden in rest zou tellen, zou je 11 krijgen, maar het eerste argument is al aan first toegewezen.

Vraag 4 van 10

Wat geeft guarded(0) terug?

function guarded(n) {
  if (n === 0) { return "empty"; }
  return "filled";
}
  1. "filled"
  2. "empty"
  3. ["empty", "filled"]
  4. undefined
Toon antwoordVerberg antwoord
Antwoord: B
De voorwaarde is waar voor 0, dus beëindigt de eerste return de aanroep direct met “empty”. De uitvoering gaat niet verder naar de latere return. Een functie geeft voor een bepaalde aanroep één waarde terug; twee return-instructies beschrijven verschillende mogelijke paden, geen verzamelde lijst met uitvoer.

Vraag 5 van 10

Wat geeft totalDown(3) terug?

function totalDown(n) {
  if (n === 0) { return 0; }
  return n + totalDown(n - 1);
}
  1. 0
  2. 6
  3. 9
  4. 3
Toon antwoordVerberg antwoord
Antwoord: B
De aanroepen bereiken totalDown(0), dat 0 teruggeeft. De wachtende aanroepen geven daarna 1, 3 en 6 terug. De retourwaarde van het basisgeval maakt niet alle resultaten van de aanroepen gelijk aan 0; elk wachtend frame heeft nog steeds een eigen n en moet de wachtende optelling voltooien.

Vraag 6 van 10

Wat gebeurt er wanneer read() wordt aangeroepen?

let label = "outer";
function read() {
  return label;
  let label = "inner";
}
  1. De aanroep geeft de string “inner” terug.
  2. De aanroep geeft de string “outer” terug.
  3. De aanroep veroorzaakt een ReferenceError.
  4. De aanroep geeft de waarde undefined terug.
Toon antwoordVerberg antwoord
Antwoord: C
De lokale declaratie overschaduwt de buitenste label in heel read, ook bij de eerdere return. Die lokale variabele is nog niet geïnitialiseerd, dus veroorzaakt het lezen ervan een ReferenceError. De onbereikbare toewijzing zorgt er niet voor dat JavaScript de lokale declaratie overslaat en de buitenste string gebruikt.

Vraag 7 van 10

Wat geeft de laatste aanroep terug?

let word = "first";
const read = () => word;
word = "second";
function run() {
  const word = "third";
  return read();
}
run();
  1. "second"
  2. undefined
  3. "first"
  4. "third"
Toon antwoordVerberg antwoord
Antwoord: A
read legt de word op het hoogste niveau vast, waarvan de huidige waarde “second” is. De functie bewaart geen vaststaande kopie van “first” en een aanroep vanuit run verlegt de zoekactie niet naar de lokale “third” van die aanroeper. Zowel de plaats van de definitie als de latere toewijzing is van belang.

Vraag 8 van 10

Welke array levert de laatste expressie op?

const readers = [];
for (let i = 1; i <= 3; i++) {
  let value = i;
  readers.push(() => value);
  value += 10;
}
readers.map((read) => read());
  1. [13, 13, 13]
  2. [1, 2, 3]
  3. [14, 14, 14]
  4. [11, 12, 13]
Toon antwoordVerberg antwoord
Antwoord: D
Elke iteratie maakt een eigen value en de bijbehorende functie behoudt die binding. De latere optelling in dezelfde iteratie verandert de waarde die de functie zal lezen in 11, 12 of 13. Bij [1, 2, 3] zou het maken van de closure als een momentopname worden behandeld en zouden die latere wijzigingen worden genegeerd.

Vraag 9 van 10

Wat gebeurt er wanneer de laatste regel wordt uitgevoerd?

function speak() { console.log("Hi"); }
function twice(action) { action(); action(); }
twice(speak());
  1. Toont één keer “Hi” en veroorzaakt daarna een TypeError.
  2. Veroorzaakt een TypeError voordat iets wordt getoond.
  3. Toont twee keer “Hi” en keert daarna normaal terug.
  4. Toont drie keer “Hi” en keert daarna normaal terug.
Toon antwoordVerberg antwoord
Antwoord: A
Bij het voorbereiden van het argument wordt speak direct aangeroepen, dus wordt “Hi” één keer getoond. De retourwaarde is undefined en wordt action; de eerste poging tot action() veroorzaakt dan een TypeError. Als je speak zonder aanroephaakjes doorgeeft, kan twice de functie twee keer aanroepen.

Vraag 10 van 10

Wat is het uiteindelijke resultaat?

const compose = (f, g) => (x) => f(g(x));
const subtract = (n) => n - 2;
const triple = (n) => n * 3;
const first = compose(triple, subtract);
const second = compose(subtract, triple);
first(second(4));
  1. 18
  2. 28
  3. 24
  4. 30
Toon antwoordVerberg antwoord
Antwoord: C
second(4) verdrievoudigt 4 en trekt er 2 van af, wat 10 teruggeeft. Dat wordt de invoer voor first, dat er 2 van aftrekt en 8 verdrievoudigt, wat 24 teruggeeft. Een resultaat van 18 past first en second in de omgekeerde buitenste volgorde toe; ook moet elke functiecompositie haar eigen aanroepvolgorde behouden, van binnen naar buiten.
Set 2: Lees functies en volg hun waarden10 Oefenvragen

Sla deze les op om elk antwoord te zien en elke set te oefenen.

Vraag 1 van 10

Gegeven function showLabel() { console.log("Ready"); }, welke instructie roept de functie aan?
  1. "showLabel";
  2. showLabel();
  3. showLabel;
  4. const label = showLabel;
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 2 van 10

Wat bevat copy na deze code?

const triple = function (n) { return n * 3; };
const copy = triple;
  1. De waarde undefined totdat copy wordt aangeroepen.
  2. Een afzonderlijke functie met gekopieerde privétoestand.
  3. Het getal dat de aanroep triple(3) teruggeeft.
  4. Een referentie naar dezelfde functie als triple.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 3 van 10

Wat geeft adjust(8) terug?

const adjust = (n) => { n - 3; };
  1. undefined
  2. 5
  3. 8
  4. NaN
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 4 van 10

Wat geeft difference(12, 5) terug?

function difference(first, second) {
  return first - second;
}
  1. 17
  2. undefined
  3. 7
  4. -7
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 5 van 10

Wat geeft readLevel(0) terug?

function readLevel(level = 40) { return level; }
  1. 40
  2. undefined
  3. null
  4. 0
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 6 van 10

Welk getal wordt getoond en wat is de waarde van result?

function displayTotal(a, b) { console.log(a + b); }
const result = displayTotal(6, 9);
  1. Toont 15; result is 15.
  2. Toont 15; result is undefined.
  3. Toont niets; result is 15.
  4. Toont undefined; result is 15.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 7 van 10

Wat gebeurt er wanneer getFlag() wordt aangeroepen?

function getFlag() {
  if (true) { let flag = "on"; }
  return flag;
}
  1. De aanroep veroorzaakt een ReferenceError.
  2. De aanroep veroorzaakt een TypeError.
  3. De aanroep geeft de waarde undefined terug.
  4. De aanroep geeft de string “on” terug.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 8 van 10

Welke waarden geven de twee aanroepen achtereenvolgens terug?

function makeStep() {
  let value = 4;
  return () => { value += 2; return value; };
}
const step = makeStep();
step();
step();
  1. 4, 6
  2. 8, 10
  3. 6, 8
  4. 6, 6
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 9 van 10

Wat is de volledige volgorde van de getoonde waarden?

function deliver(action) { action(7); }
console.log("start");
deliver((n) => console.log(n));
console.log("end");
  1. "start", 7, "end"
  2. "start", undefined, "end"
  3. "start", "end", 7
  4. 7, "start", "end"
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 10 van 10

Wat is de uiteindelijke waarde van result?

const values = [2, 7, 4, 9];
const result = values
  .filter((n) => n > 3)
  .map((n) => n - 1)
  .reduce((total, n) => total + n, 5);
  1. 27
  2. 22
  3. 17
  4. 21
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Set 3: Verbind aanroepen, bereik en callbacks10 Oefenvragen

Sla deze les op om elk antwoord te zien en elke set te oefenen.

Vraag 1 van 10

Wat gebeurt er wanneer dit script wordt uitgevoerd?

const saved = build;
const build = function () { return 9; };
console.log(saved());
  1. Het veroorzaakt een ReferenceError op de eerste regel.
  2. Het veroorzaakt een TypeError op de laatste regel.
  3. Het toont undefined op de laatste regel.
  4. Het toont 9 nadat de toewijzing is voltooid.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 2 van 10

Welke waarde wordt toegewezen aan out?

const describe = (n) => {
  const doubled = n * 2;
  return doubled + 1;
};
const out = describe(6);
  1. undefined
  2. 7
  3. 13
  4. 12
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 3 van 10

Wat zijn items en answer na deze code?

const items = [5];
function change(list) {
  list.push(8);
  list = [1];
  return list;
}
const answer = change(items);
  1. items is [5, 8]; answer is [5, 8].
  2. items is [5]; answer is [1].
  3. items is [1]; answer is [1].
  4. items is [5, 8]; answer is [1].
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 4 van 10

Wat geeft countLeaves([0, [[], 2], [[3], 4]]) terug?

function countLeaves(list) {
  let count = 0;
  for (const item of list) {
    if (Array.isArray(item)) {
      count += countLeaves(item);
    } else {
      count++;
    }
  }
  return count;
}
  1. 6
  2. 4
  3. 3
  4. 5
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 5 van 10

Wat geeft readValue() terug?

function readValue() {
  if (true) { var value = 14; }
  return value;
}
  1. 14
  2. undefined
  3. De aanroep veroorzaakt een ReferenceError.
  4. De aanroep veroorzaakt een TypeError.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 6 van 10

Welke twee waarden worden getoond?

let count = 2;
function update() {
  let count = 7;
  count += 1;
  return count;
}
console.log(update());
console.log(count);
  1. 3, 3
  2. 7, 2
  3. 8, 2
  4. 8, 8
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 7 van 10

Welke waarden geven de laatste drie aanroepen terug?

function makeCounter(start) {
  let n = start;
  return () => { n++; return n; };
}
const a = makeCounter(5);
const alias = a;
const b = makeCounter(5);
a();
alias();
b();
  1. 5, 6, 5
  2. 6, 7, 6
  3. 6, 7, 8
  4. 6, 6, 6
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 8 van 10

Wat geeft scale(7) terug?

const makeScale = (factor) => (n) => n * factor;
const scale = makeScale(4);
  1. 7
  2. 11
  3. Een nieuwe functie.
  4. 28
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 9 van 10

Wat zijn values en first daarna?

const values = [12, 3, 20];
const first = values.sort((a, b) => a - b)[0];
  1. values is [12, 3, 20]; first is 3.
  2. values is [3, 12, 20]; first is 3.
  3. values is [20, 12, 3]; first is 20.
  4. values is [12, 20, 3]; first is 12.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 10 van 10

Wat geven de aanroepen read(0) en read(9) achtereenvolgens terug?

function once(fn) {
  let done = false;
  let result;
  return (...args) => {
    if (!done) {
      done = true;
      result = fn(...args);
    }
    return result;
  };
}
const read = once((n) => n * 2);
  1. undefined, 18
  2. 0, 18
  3. 0, 0
  4. 0, undefined
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Set 4: Onderzoek functiegedrag in kleine programma's10 Oefenvragen

Sla deze les op om elk antwoord te zien en elke set te oefenen.

Vraag 1 van 10

Een script definieert function printLine() { console.log("---"); } en voert daarna printline(); uit. Wat gebeurt er?
  1. De aanroep geeft undefined terug zonder iets te tonen.
  2. Er wordt één regel getoond en de uitvoering gaat verder.
  3. Er ontstaat een TypeError en er wordt geen regel getoond.
  4. Er ontstaat een ReferenceError en er wordt geen regel getoond.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 2 van 10

Wat geeft de laatste aanroep terug?

const climb = function step(n) {
  return n === 0 ? 0 : 1 + step(n - 1);
};
const saved = climb;
saved(2);
  1. 0
  2. 2
  3. De aanroep veroorzaakt een ReferenceError.
  4. 1
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 3 van 10

Wat zijn data en result aan het eind?

const data = [2, 5];
function extend(list, item) {
  const next = list.concat(item);
  list.push(9);
  return next;
}
const result = extend(data, 7);
result.push(1);
  1. data is [2, 5, 9]; result is [2, 5, 7, 1].
  2. data is [2, 5, 9, 1]; result is [2, 5, 7, 1].
  3. data is [2, 5, 7, 9]; result is [2, 5, 7, 9, 1].
  4. data is [2, 5]; result is [2, 5, 7, 9, 1].
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 4 van 10

Wat geeft de laatste aanroep terug?

function total(base = 4, ...extras) {
  return extras.reduce((sum, n) => sum + n, base);
}
const values = [undefined, 3, 0, 8];
total(...values);
  1. NaN
  2. 11
  3. 15
  4. 19
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 5 van 10

Welke waarde levert deze aanroep op?

function read() {
  return;
}
read();
  1. undefined
  2. null
  3. false
  4. 0
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 6 van 10

De invoer n is een niet-negatief geheel getal. Welke vervanging van de recursieve return laat de functie voor zowel oneven als even invoer correct aftellen tot 0?

function countDown(n) {
  if (n === 0) { return 0; }
  // recursive return goes here
}
  1. return 1 + countDown(n - 2);
  2. return 1 + countDown(n - 1);
  3. return 1 + countDown(n);
  4. return 1 + countDown(n + 1);
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 7 van 10

Wat geeft de laatste aanroep terug?

const mode = "shared";
function readMode() { return mode; }
function run() {
  const mode = "local";
  return readMode();
}
run();
  1. De aanroep veroorzaakt een ReferenceError.
  2. undefined
  3. "local"
  4. "shared"
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 8 van 10

Welke waarden geven jobs[0]() en jobs[1]() na de lus terug?

const jobs = [];
for (var i = 0; i < 2; i++) {
  const offset = i * 10;
  jobs.push(() => offset + i);
}
  1. 12, 12
  2. 0, 10
  3. 2, 12
  4. 0, 11
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 9 van 10

Welk resultaat levert deze expressie op?

["6", "8", "10"].map((text) => parseInt(text, 10));
  1. [6, NaN, NaN]
  2. [6, 8, 10]
  3. [6, NaN, 2]
  4. ["6", "8", "10"]
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 10 van 10

Wat zijn de getoonde waarden van out en seen?

let seen = 0;
const out = [3, 5].forEach((n) => {
  seen += n;
  return n * 2;
});
console.log(out, seen);
  1. undefined, 8
  2. [6, 10], 8
  3. undefined, 16
  4. [6, 10], 0
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Set 5: Combineer closures en hogere-ordefuncties10 Oefenvragen

Sla deze les op om elk antwoord te zien en elke set te oefenen.

Vraag 1 van 10

Welke pijlfunctie geeft de som van haar twee invoerwaarden terug?
  1. (a, b) => { console.log(a + b); }
  2. (a, b) => { return a + b; }
  3. (a, b) => { return; a + b; }
  4. (a, b) => { a + b; }
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 2 van 10

Tot welke waarde wordt add("6", 4) * 2 geëvalueerd?

function add(a, b) { return a + b; }
  1. 20
  2. NaN
  3. 128
  4. "6464"
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 3 van 10

Tot welke waarde wordt de laatste expressie geëvalueerd?

function choose(n) {
  if (n < 0) { return 0; }
  return n + 2;
}
choose(choose(-4));
  1. 2
  2. -2
  3. 0
  4. 4
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 4 van 10

Wat gebeurt er wanneer build() wordt aangeroepen?

let amount = 6;
function build() {
  const read = () => amount;
  const result = read();
  let amount = 9;
  return result;
}
  1. De aanroep geeft het getal 6 terug.
  2. De aanroep geeft het getal 9 terug.
  3. De aanroep geeft de waarde undefined terug.
  4. De aanroep veroorzaakt een ReferenceError binnen read.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 5 van 10

Welke waarden geven change(3), read() en otherRead() terug?

function makePair() {
  let n = 1;
  return [
    (step) => { n += step; return n; },
    () => n
  ];
}
const [change, read] = makePair();
const [, otherRead] = makePair();
  1. 4, 1, 1
  2. 4, 4, 4
  3. 3, 3, 1
  4. 4, 4, 1
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 6 van 10

Wat geeft de laatste expressie terug?

function makeLimit(max) {
  let used = 0;
  return () => {
    if (used >= max) { return false; }
    used++;
    return true;
  };
}
const allow = makeLimit(2);
[allow(), allow(), allow()];
  1. [true, true, true]
  2. [true, true, false]
  3. [true, false, false]
  4. [false, false, false]
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 7 van 10

Wat zijn result en calls na deze code?

let calls = 0;
function choose(values, test) {
  for (const value of values) {
    calls++;
    if (test(value)) { return value; }
  }
  return null;
}
const result = choose([3, 8, 10, 5], (n) => n > 6 && n % 2 === 0);
  1. result is 8; calls is 2.
  2. result is [8, 10]; calls is 4.
  3. result is 8; calls is 4.
  4. result is 10; calls is 3.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 8 van 10

Wat zijn items en out daarna?

const items = [2, 4, 6];
const out = items.map((n, index, array) => {
  array[index] = n + 1;
  return n * 2;
});
  1. items is [4, 8, 12]; out is [3, 5, 7].
  2. items is [3, 5, 7]; out is [6, 10, 14].
  3. items is [3, 5, 7]; out is [4, 8, 12].
  4. items is [2, 4, 6]; out is [4, 8, 12].
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 9 van 10

Wat geeft doubleSaved(9) terug na de getoonde eerdere aanroep?

function once(fn) {
  let done = false;
  let saved;
  return (...args) => {
    if (!done) { done = true; saved = fn(...args); }
    return saved;
  };
}
const compose = (f, g) => (x) => f(g(x));
const saved = once((n) => n + 3);
const doubleSaved = compose((n) => n * 2, saved);
saved(4);
doubleSaved(9);
  1. 18
  2. 14
  3. 7
  4. 24
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 10 van 10

Wat is de teruggegeven array?

const partial = (fn, ...fixed) => (...later) => fn(...fixed, ...later);
const offset = (base, n) => base + n;
const addFive = partial(offset, 5);
const compose = (f, g) => (x) => f(g(x));
const transform = compose((n) => n * n, addFive);
[1, 3].map(transform);
  1. [12, 16]
  2. [6, 14]
  3. [36, 64]
  4. [26, 28]
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Kom je niet uit je eigen opgave? Huiswerkhulp

Kernbegrippen

66 Kernbegrippen, elk met een definitie

A

aanroepspoor
Een aanroepspoor vermeldt de aanroepen die actief waren toen een fout optrad, te beginnen met de meest recente aanroep en daarna de aanroepen die daartoe leidden.
Herhaalde vermeldingen van één recursieve functie kunnen helpen een stopvoorwaarde te vinden die de invoer nooit bereikt.
aanroepstapel
De aanroepstapel houdt onvoltooide functieaanroepen bij, plaatst elke nieuwe aanroep bovenop en verwijdert het frame wanneer die aanroep terugkeert.
Terwijl sumOfSquares op square(3) wacht, heeft de aanroep van square een frame boven de wachtende aanroeper.
accumulator
Een accumulator is het lopende resultaat van een reductie, dat aan de callback wordt doorgegeven en bij elke stap wordt vervangen door de waarde die die callback teruggeeft.
Een somreductie die bij 0 begint, werkt de accumulator bij naar 5, 15 en 30 tijdens het verwerken van [5, 10, 15].
anonieme functie
Een anonieme functie is een functie-expressie zonder expliciete functienaam, die vaak in een variabele wordt opgeslagen of als argument wordt doorgegeven.
De expressie function (n) { return n * n; } heeft in de geschreven syntaxis geen interne functienaam.
argument
Een argument is een waarde die aan een functieaanroep wordt meegegeven en op positie aan een parameter wordt gekoppeld of bij de resterende invoer wordt verzameld.
In area(4, 2.5) zijn de argumenten 4 en 2,5, ongeacht hoe de parameters zijn genoemd.
arguments-object
Het arguments-object is een collectie die op een array lijkt en de invoer bevat die aan een gewone functie is doorgegeven. Het is geen echte restparameterarray.
Oudere code kan arguments[0] lezen, maar kan arguments.map niet als gewone arraymethode aanroepen.
arraydestructurering
Arraydestructurering wijst items uit een array toe aan afzonderlijke namen, zodat één teruggegeven array meerdere benoemde resultaten kan leveren.
De declaratie const [low, high] = minMax(values); pakt de twee items van de teruggegeven array uit.

B

basisgeval
Een basisgeval is het stoppad van een recursieve functie, dat een waarde teruggeeft zonder nog een aanroep van zichzelf wanneer het probleem een eenvoudige vorm heeft bereikt.
Voor een faculteitsberekening met niet-negatieve gehele getallen stopt de test n <= 1 de aanroepen bij 0 of 1.
benoemde functie-expressie
Een benoemde functie-expressie maakt een functie met een interne naam die binnen het eigen functielichaam beschikbaar is, ook voor recursieve aanroepen.
In const factorial = function fact(n) { /* body */ }; is factorial de variabele voor buiten de functie en fact de interne naam.
bereikketen
De bereikketen is de reeks van het huidige bereik en de omvattende bereiken die naar buiten toe wordt doorzocht om een naam op te zoeken, waarbij het zoeken stopt bij de eerste declaratie.
Een binnenste berekening leest de lokale amount voordat een variabele met dezelfde naam in een buitenste bereik wordt bekeken.
bewakingsclausule
Een bewakingsclausule controleert een bijzondere voorwaarde en keert vroegtijdig terug, zodat dat uitzonderlijke pad gescheiden blijft van de hoofdtaak van de functie.
De test if (b === 0) { return null; } beschermt de deling die erna in safeDivide staat.
binding
Een binding koppelt een naam aan een opgeslagen waarde in een bepaald bereik, zodat variabelen met dezelfde naam in verschillende bereiken van elkaar onderscheiden blijven.
Een toewijzing werkt de dichtstbijzijnde toegankelijke binding bij; een binnenste declaratie maakt een afzonderlijke lokale binding.
binding per iteratie
Een binding per iteratie is de afzonderlijke binding van een lusvariabele die let in de kop van een for-lus voor een iteratie maakt en die closures kunnen behouden.
Opgeslagen pijlfuncties uit verschillende iteraties met let i kunnen na afloop van de lus verschillende waarden teruggeven.
blokbereik
Blokbereik beperkt een let- of const-declaratie tot het omvattende blok en geneste code, zodat die declaratie niet beschikbaar is voor code daarbuiten.
Een let message die in een if-blok is gedeclareerd, kan niet worden gelezen door een instructie na het einde van dat blok.

C

callback
Een callback is een functie die als argument wordt doorgegeven zodat een ontvanger die kan aanroepen, waarbij die ontvanger de invoer en het gebruik van de retourwaarde bepaalt.
Een hulpfunctie countIf roept voor elk item de testcallback aan en telt de items waarvan het testresultaat truthy is.
camelCase
CamelCase is een naamgevingsstijl met een kleine letter aan het begin van het eerste woord en hoofdletters aan het begin van latere woorden. Deze stijl wordt vaak gebruikt voor JavaScript-functienamen.
De naam calculateTotal beschrijft een handeling en onderscheidt de twee woorden zonder spaties of underscores.
closure
Een closure combineert een functie met behouden toegang tot het bereik waarin die is gemaakt, zodat vastgelegde variabelen bruikbaar kunnen blijven nadat de buitenste functie is teruggekeerd.
Een tellerfunctie kan haar privévariabele count blijven verhogen nadat de fabriek die haar maakte is beëindigd.

D

direct aangeroepen functie-expressie
Een direct aangeroepen functie-expressie, of IIFE, maakt een functie en roept die meteen aan, vaak om oudere code een privébereik te geven.
De laatste ronde haakjes in (function () { var hidden = 1; })(); roepen de zojuist gemaakte functie aan.

E

expressie als functielichaam
Een expressie als functielichaam is een functielichaam van een pijlfunctie waarvan de waarde het resultaat van de aanroep wordt zonder expliciete return-instructie.
De expressie als functielichaam in (a, b) => a + b geeft direct de som van de twee doorgegeven argumenten terug.

F

falsy-waarde
Een falsy-waarde gedraagt zich als onwaar in een waarheidstest. Daarom kan een oudere standaardwaarde met logische OF geldige invoer zoals nul vervangen.
De expressie level || 50 vervangt 0, terwijl een standaardwaarde van een parameter die doorgegeven waarde behoudt.
functie
Een functie is een herbruikbare verzameling instructies die bij een aanroep een taak uitvoert en eventueel invoer accepteert en een resultaat teruggeeft.
Een script roept printHeading("Report") en printHeading("Totals") aan om dezelfde routine voor een kop te hergebruiken.
functie-expressie
Een functie-expressie maakt een functie als waarde binnen een expressie, zoals aan de rechterkant van een toewijzing aan een variabele.
In const square = function (n) { return n * n; }; levert de expressie de waarde die in square wordt opgeslagen.
functieaanroep
Een functieaanroep roept een functie aan met ronde haakjes na een functiewaarde, met eventuele argumenten tussen die haakjes.
Als je sayHi() schrijft, wordt het functielichaam uitgevoerd, terwijl een regel met alleen sayHi de functiewaarde leest.
functiebereik
Functiebereik maakt een parameter of var-declaratie lokaal voor de omvattende functie, ook wanneer de var binnen een binnenste blok is geschreven.
Een var result die in een if-blok een waarde krijgt, kan later vanuit het omvattende functielichaam worden teruggegeven.
functiecompositie
Functiecompositie combineert functies door de uitvoer van de ene functie door te geven aan de invoer van een andere, waarbij de binnenste aanroep vóór de buitenste wordt uitgevoerd.
Bij f(g(x)) kan een wijziging van de volgorde naar g(f(x)) het resultaat veranderen, ook als beide functies getallen accepteren.
functiedeclaratie
Een functiedeclaratie definieert met het sleutelwoord function een benoemde functie en maakt die vanaf het begin van het bereik beschikbaar.
De aanroep greet("Li") kan binnen hetzelfde bereik boven de geschreven declaratie van greet staan.
functiefabriek
Een functiefabriek maakt ingestelde functies en geeft die terug, waarbij toegang via een closure de argumenten of lokale toestand van de aanroep behoudt.
De aanroep makeMultiplier(3) geeft een functie terug die 3 onthoudt en later een getal accepteert om mee te vermenigvuldigen.
functielichaam
Een functielichaam bevat de instructies die tijdens een aanroep worden uitgevoerd; een gewone functie zet die instructies tussen accolades.
Als het functielichaam van printHeading drie instructies bevat die iets tonen, worden ze alle drie bij elke aanroep van die functie opnieuw uitgevoerd.
functiereferentie
Een functiereferentie is een waarde die een functie aanduidt, zodat een andere variabele of ontvanger later dezelfde functie kan aanroepen.
Na const alias = square; roept alias(4) de functie aan die ook via square bereikbaar is.

G

gedeelde toestand
Gedeelde toestand zijn behouden gegevens die meer dan één functie kan bereiken en bijwerken, zoals één binding die is vastgelegd door functies uit dezelfde aanroep.
Een stortingsbewerking en een functie die het saldo leest en samen zijn teruggegeven, kunnen allebei dezelfde privévariabele balance bereiken.
globaal bereik
Het globale bereik bevat declaraties op het hoogste niveau van een gewoon script en maakt die namen beschikbaar voor functies waarvan de bereikketen ze bereikt.
Een count op het hoogste niveau van een script kan gedeelde toestand worden wanneer meerdere functies die lezen of bijwerken.

H

hertoewijzing
Hertoewijzing verandert de waarde die in een bestaande variabele of parameter is opgeslagen, zonder een andere variabele te wijzigen die de oude waarde bevatte.
Binnen een functie laat arr = [] de parameter naar iets anders verwijzen zonder de arrayreferentie van de aanroeper te vervangen.
hogere-ordefunctie
Een hogere-ordefunctie accepteert een functie als argument, geeft een functie als resultaat terug of combineert beide manieren om functiewaarden te verwerken.
Arraymethoden accepteren callbacks, terwijl een vermenigvuldigingsfabriek een ingestelde berekeningsfunctie teruggeeft.
hoisting
Hoisting beschrijft dat declaraties worden geregistreerd voordat hun bereik wordt uitgevoerd, met verschillende regels voor vroege toegang bij functies, var, let en const.
Als je een var waarop hoisting is toegepast vóór de toewijzing leest, krijg je undefined; een vroege aanroep van een functiedeclaratie kan worden uitgevoerd.

I

inlinefunctie
Een inlinefunctie is een functie-expressie die direct wordt geschreven waar de waarde nodig is, zoals een pijlfunctie binnen de argumentenlijst van een aanroep.
De pijlfunctie in repeat(3, (i) => console.log(i)) levert de handeling zonder afzonderlijke benoemde declaratie.
instructieblok als functielichaam
Een instructieblok als functielichaam bevat instructies tussen accolades en heeft een expliciete return nodig om vanuit een pijlfunctie een berekende waarde terug te geven.
De pijlfunctie (n) => { n * 2; } berekent een product maar geeft undefined terug omdat er geen return-instructie is.

L

lexicaal bereik
Lexicaal bereik bepaalt toegankelijke buitenste declaraties op basis van hoe code in elkaar is genest, en niet op basis van de plaats van een latere aanroeper.
Een leesfunctie op het hoogste niveau leest nog steeds haar buitenste variabele wanneer ze wordt aangeroepen binnen een functie met een lokale variabele met dezelfde naam.
lokale variabele
Een lokale variabele hoort bij een beperkt functie- of blokbereik, zodat de bijbehorende werkgegevens gescheiden blijven van buitenste gegevens met een vergelijkbare naam.
Twee onafhankelijke functies kunnen elk een lokale total gebruiken zonder dat hun optellingen elkaar beïnvloeden.

M

methodeketen
Een methodeketen gebruikt de retourwaarde van de ene methode als ontvanger van de volgende methode, zodat meerdere stappen voor arrayverwerking achtereenvolgens mogelijk zijn.
Een filter gevolgd door een map-methode selecteert eerst invoer en transformeert daarna alleen de behouden items.
mutatie
Mutatie verandert de inhoud van een bestaande waarde zoals een array, waardoor de wijziging zichtbaar wordt via andere referenties naar die array.
Een functie die arr.push(3) aanroept, wijzigt dezelfde array die de aanroeper als argument heeft doorgegeven.

N

neveneffect
Een neveneffect is een verandering buiten de lokale berekening van een functie, zoals iets tonen, een buitenste variabele wijzigen of een invoerarray veranderen.
Een callback die met push iets aan een gedeelde lijst toevoegt, heeft een neveneffect, ook als die een bruikbare waarde teruggeeft.

O

objectliteral
Een objectliteral maakt een object met accolades en benoemde eigenschappen; om die vanuit een expressie als functielichaam terug te geven, zet je de objectliteral tussen ronde haakjes.
De pijlfunctie (n) => ({ value: n }) geeft een object terug in plaats van de accolades als een instructieblok te behandelen.
omhullende functie
Een omhullende functie is een teruggegeven functie die gedrag toevoegt rond een bestaande functieaanroep, vaak door de invoer door te geven en het resultaat te behouden.
Een omhullende functie voor registratie toont de doorgegeven argumenten, roept de oorspronkelijke functie aan en geeft daarna het resultaat terug.
omhullende functie voor eenmalige uitvoering
Een omhullende functie voor eenmalige uitvoering behoudt een voltooiingsvlag en een eerste resultaat, zodat latere aanroepen dat resultaat kunnen hergebruiken zonder een voltooide bewerking te herhalen.
Met een afzonderlijke vlag kan een omhullende functie voor eenmalige uitvoering onthouden dat de eerste aanroep is voltooid, ook wanneer het resultaat 0 was.
overschaduwing
Overschaduwing ontstaat wanneer een binnenste declaratie binnen het binnenste bereik een buitenste declaratie met dezelfde naam verbergt en de naam zo een andere binding krijgt.
Een parameter met de naam count verbergt binnen die functie een buitenste count zonder de buitenste binding te wijzigen.

P

parameter
Een parameter is een lokale naam in een functiedefinitie die bij de aanroep van de functie een waarde uit een argument ontvangt.
De namen width en height zijn parameters in function area(width, height) { return width * height; }.
parameter met een standaardwaarde
Een parameter met een standaardwaarde gebruikt een opgegeven expressie wanneer het argument undefined is, ook wanneer de aanroeper dat argument weglaat.
De parameter level = 50 behoudt een expliciete 0 maar levert 50 wanneer het argument ontbreekt.
partiële toepassing
Partiële toepassing legt geselecteerde argumenten vooraf vast en geeft een functie terug die de resterende invoer levert wanneer die later wordt aangeroepen.
Een begroetingsfunctie waarbij “Hello” als argument is vastgelegd door partiële toepassing, kan later “Ana” accepteren en “Hello, Ana” teruggeven.
pijlfunctie
Een pijlfunctie is een functie-expressie met een pijl tussen de parameters en het functielichaam, zonder eigen binding voor this of arguments.
De pijlfunctie (n) => n * 2 levert een korte transformatiecallback aan een arraymethode zoals map.
predicaat
Een predicaat is een testfunctie waarvan het resultaat bepaalt of invoer aan een voorwaarde voldoet, gebruikt door methoden zoals filter of find.
Het predicaat (n) => n > 4 selecteert welke getallen een filter behoudt zonder hun waarden zelf te wijzigen.
privétoestand
Privétoestand bestaat uit gegevens binnen het lokale bereik van een closure die code daarbuiten alleen kan bereiken of wijzigen via de bewerkingen die toegang ertoe bieden.
Een begrenzer biedt een bewerking die toestaat of afwijst, terwijl de interne teller used niet direct toegankelijk is.

R

recursie
Recursie treedt op wanneer een functie zichzelf aanroept om kleinere versies van een taak op te lossen, met een stopgeval dat geen verdere aanroep van zichzelf nodig heeft.
Een faculteitsfunctie vermenigvuldigt haar invoer met het resultaat van dezelfde functie voor een invoer die één kleiner is.
recursief geval
Een recursief geval behandelt het probleem door dezelfde functie met een kleinere invoer aan te roepen en het teruggegeven resultaat te gebruiken om de huidige aanroep te voltooien.
De expressie n * factorial(n - 1) wacht op de kleinere faculteit voordat die met de n van deze aanroep wordt vermenigvuldigd.
restparameter
Een restparameter verzamelt resterende argumenten van een aanroep in een echte array en staat als laatste parameter, voorafgegaan door drie punten.
In function log(label, ...values) { /* body */ } staat het eerste argument los van de restarray.
retourwaarde
Een retourwaarde is de ene waarde die een functieaanroep oplevert en aan de aanroeper geeft om op te slaan of in een andere expressie te gebruiken.
Als double(5) de waarde 10 teruggeeft, kan de expressie double(5) + 1 die waarde direct gebruiken om 11 te maken.

S

spreadsyntaxis
Spreadsyntaxis pakt array-items uit in afzonderlijke argumenten voor een aanroep, met drie punten vóór de arrayexpressie in de argumentenlijst.
De aanroep Math.max(...[3, 7, 2]) geeft drie getallen door aan Math.max in plaats van één array.
stapelframe
Een stapelframe bevat de uitvoeringstoestand van één actieve functieaanroep, met onder meer de parameters, lokale variabelen en het punt waar de uitvoering verdergaat.
Twee actieve recursieve aanroepen kunnen elk een andere waarde van n bewaren omdat ze afzonderlijke frames hebben.
strikte modus
Strikte modus is een uitvoeringsmodus van JavaScript die toewijzing aan niet-gedeclareerde namen afwijst en zo onbedoelde globale variabelen helpt voorkomen.
Als een gewoon script begint met "use strict";, veroorzaakt een niet-gedeclareerde toewijzing count = 5; een ReferenceError.
synchrone callback
Een synchrone callback wordt tijdens de uitvoering van de ontvangende functie uitgevoerd en voltooit het werk voordat die ontvanger naar de eigen aanroeper terugkeert.
Een map-callback verwerkt array-items voordat de voltooide aanroep van map de resultaatarray levert.

T

tijdelijke dode zone
De tijdelijke dode zone is de periode vóór initialisatie van een let- of const-binding waarin toegang tot die binding een ReferenceError veroorzaakt.
Een vroege leesactie vindt een overschaduwende lokale variabele ook als die nog niet is geïnitialiseerd, in plaats van een buitenste waarde te gebruiken.
transformatiecallback
Een transformatiecallback geeft een vervangende waarde voor een invoeritem terug, zodat een transformatiefunctie de uitvoer in een nieuwe array kan verzamelen.
De callback (n) => n * n zet de items van [1, 2, 3] via een transformatiebewerking om in kwadraten.

U

uitgestelde callback
Een uitgestelde callback wordt ingepland om later te worden uitgevoerd, terwijl code na de aanroep die de uitvoering inplant kan doorgaan zonder op die callback te wachten.
Als je sayHi aan setTimeout doorgeeft, kunnen de volgende instructies worden uitgevoerd voordat de ingeplande begroeting verschijnt.

V

vastgelegde variabele
Een vastgelegde variabele is een binding die via een closure wordt bereikt, zodat de functie de huidige waarde kan lezen in plaats van een vaststaande kopie van het moment waarop de functie werd gemaakt.
Als een buitenste greeting van “Hi” in “Hello” verandert, verandert de waarde die een latere aanroep van een functie die greeting leest, teruggeeft.
vergelijkingsfunctie
Een vergelijkingsfunctie is een sorteercallback waarvan de retourwaarde, negatief, positief of nul, de onderlinge volgorde van twee vergeleken invoerwaarden bepaalt.
De vergelijkingsfunctie (a, b) => a - b sorteert getallen in oplopende volgorde terwijl sort de invoerarray herschikt.
voortijdig terugkeren
Voortijdig terugkeren beëindigt een aanroep voordat de latere instructies worden uitgevoerd, vaak om speciale invoer af te handelen voordat de functie haar hoofdtaak uitvoert.
Een hulpfunctie voor deling kan null teruggeven bij nul als deler voordat de uitvoering de delingsinstructie bereikt.

Z

zuivere functie
Een zuivere functie berekent haar uitvoer uitsluitend uit haar argumenten en brengt geen wijzigingen buiten de aanroep aan, dus ook geen console-uitvoer.
Een functie die alleen n * 2 teruggeeft is zuiver; het product tonen zou een neveneffect toevoegen.

Over deze les

Door StudeliFout melden

Maak je eigen Studiemateriaal

Maak van je aantekeningen, slides en documenten Leermodules, Oefenvragen, Flashcards en 6 andere tools.

Aan de slag