JavaScript-functies, bereik en closures
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
- 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 aanDefinieer 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-expressieBehandel 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 pijlfunctiesGebruik de korte pijlsyntaxis, weet wanneer een pijlfunctie automatisch een waarde teruggeeft en leg uit hoe pijlfuncties verschillen van functies die met
functionzijn geschreven.
- Schrijf een functiedeclaratie en roep de functie aan
- 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 parametersLeg 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 argumentenGeef parameters standaardwaarden, verzamel een willekeurig aantal argumenten met een restparameter en pak een array uit in afzonderlijke argumenten.
- Geef resultaten terug vanuit een functieGeef 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 aanroepstapelVolg de volgorde waarin geneste aanroepen worden uitgevoerd en terugkeren, en schrijf een eenvoudige recursieve functie met een basisgeval.
- Koppel argumenten aan parameters
- 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 bereikLeg het bereik uit van een variabele die met
let,constofvaris gedeclareerd en gebruik lokale variabelen om functies onafhankelijk van elkaar te houden. - Voorspel naar welke variabele een naam verwijstVolg de bereikketen om de variabele achter een naam te vinden, herken overschaduwing en leg hoisting en de tijdelijke dode zone uit.
- Onderscheid blokbereik, functiebereik en globaal bereik
- 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 onthoudtBeschrijf 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étoestandBouw functiefabrieken, houd gegevens privé achter functies en voorkom de klassieke fout met closures in een lus.
- Leg uit wat een closure onthoudt
- 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 functieGeef 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-ordefunctiesHerken 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 functiesSchrijf hogere-ordefuncties die andere functies omhullen, combineren of vooraf van argumenten voorzien en gebruik closures om de ontvangen functie te onthouden.
- Geef een callback door aan een functie
JavaScript-functies: uitleg
1Definieer 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:
| Vorm | Vóó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
squaretoewijst, kopieer je een functiereferentie; als jesquare(3)toewijst, sla je het resultaat op. - Een functie-expressie die in
constis opgeslagen, kun je pas na initialisatie aanroepen. - Een functievariabele met
varbevatundefinedvoordat 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
| Functielichaam | Voorbeeld | Resultaat van de aanroep met 2 en 3 |
|---|---|---|
| Expressie | (a, b) => a + b | 5 |
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
returnnodig 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
thisofargumentsen kunnen geen constructor zijn.
2Geef 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 ... | Taak | Voorbeeld |
|---|---|---|
| Parameterlijst van de definitie | Resterende argumenten verzamelen | function sum(...numbers) { ... } |
| Argumentenlijst van de aanroep | Array-elementen uitpakken | sum(...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 ennull. - 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
returnlevert 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:
factorial(4)wacht opfactorial(3).- Die aanroep wacht op
factorial(2). - Die aanroep wacht op
factorial(1). - Het basisgeval geeft 1 terug.
- 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.
3Leg 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
| Declaratie | Grens |
|---|---|
let of const binnen een blok | Dat blok |
var binnen een functie | De omvattende functie, ook wanneer de declaratie in een binnenste blok staat |
| Declaratie op het hoogste niveau in een gewoon script | Het globale bereik van het script |
| Declaratie op het hoogste niveau in een module | Die 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
letenconstvolgen blokgrenzen;varvolgt 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:
| Declaratie | Vóór de initialisatieregel |
|---|---|
| Functiedeclaratie | De functie is beschikbaar |
var | De waarde is undefined |
let of const | Toegang 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.
varbegint alsundefined;letenconstzijn niet toegankelijk in hun TDZ.- Een toewijzing werkt een bestaande binding bij; een declaratie maakt er een.
constvoorkomt hertoewijzing, terwijl de inhoud van een array nog kan veranderen.- Een herhaalde declaratie in één bereik verschilt van overschaduwing in een genest bereik.
4Gebruik 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
vardelen één binding; lusiteraties metletkrijgen afzonderlijke bindingen. - Een IIFE maakt een functiebereik en voert de functie direct uit.
- Bereikbare closures houden de vastgelegde gegevens die ze nodig hebben bereikbaar.
5Geef 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
| Methode | Taak van de callback | Resultaat van de methode |
|---|---|---|
map | Elke getransformeerde waarde teruggeven | Een nieuwe array van dezelfde lengte |
filter | Een truthy-waarde teruggeven voor items die behouden moeten blijven | Een nieuwe array met geselecteerde items |
find | Testen op een passend item | Eerste overeenkomst, of undefined |
forEach | Voor elk item een handeling uitvoeren | undefined |
reduce | De volgende accumulator teruggeven | De 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,filterenfindgebruiken resultaten van callbacks op verschillende manieren.forEachgeeftundefinedterug;reducegeeft 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)pastgtoe vóórf.- Partiële toepassing legt geselecteerde argumenten vast vóór latere aanroepen.
JavaScript-functies: voorbeelden
1Maak een functie, sla die op en roep die aan
11 stappen
- 1IntroductieOnderscheid 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.
- 2VoorbeeldDefinieer 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.
nameis 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. - 3VoorbeeldVoer 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
greetalleen is de functiewaarde. De ronde haakjes ingreet("Li")vragen om uitvoering. Ook een functie zonder invoer heeft bij een aanroep ronde haakjes nodig, zoals insayHi(). - 4UitdagingVoorspel 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 alleenshow;zou de functie lezen zonder iets te tonen. - 5UitlegBewaar de functie als waarde
const square = function (n) { return n * n; }; const alias = square;De expressie maakt een functie en
squareslaat die op. De tweede toewijzing kopieert de referentie naaralias; er wordt geen kwadraat berekend. Zowelsquare(3)alsalias(3)geeft 9 terug.Ter vergelijking:
const answer = square(3);roept de functie aan en slaat het teruggegeven getal op. - 6UitdagingZoek waar het eerst misgaat
Toont dit script 16?
console.log(square(4)); const square = function (n) { return n * n; };---reveal---
Nee. Als je
squareleest vóór de initialisatie metconst, krijg je eenReferenceError. 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. - 7VoorbeeldGebruik 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 enadd(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 dezeconst-variabelen nog steeds vóór gebruik worden geïnitialiseerd. - 8UitdagingHerstel een ontbrekend resultaat
Waarom geeft
add(2, 3)de waardeundefinedterug 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. - 9TipGeef 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
thisofargumentsen kunnen geen constructor zijn. De korte vorm werkt goed voor eenvoudige berekeningen, maar deze verschillen zijn van belang wanneer je andere soorten functies omzet. - 10UitdagingVolg 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
copybevat dezelfde aanroepbare functie alsadjust. De toewijzing heeft de functie niet aangeroepen of een numeriek resultaat opgeslagen. Als jeconst copy = adjust;zou vervangen doorconst copy = adjust(5);, zou je 7 opslaan en dat is niet aanroepbaar. - 11SamenvattingLees 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
returnnodig.Onderscheid bij het volgen van code een functiedefinitie, een referentietoewijzing en een aanroep. Dat zijn verschillende bewerkingen, ook als ze dezelfde naam gebruiken.
2Volg invoer, uitvoer en wachtende aanroepen
16 stappen
Sla deze les op om elke Walkthrough stap voor stap te volgen.
- 1IntroductieVolg wat een aanroep ontvangt en teruggeeft
- 2VoorbeeldKoppel argumenten op positie
- 3VoorbeeldOnderscheid mutatie van hertoewijzing
- 4UitdagingBehoud de oorspronkelijke invoer
- 5UitlegEen standaardwaarde geldt bij undefined
- 6VoorbeeldVerzamel en pak daarna uit
- 7UitdagingGebruik een standaardwaarde met rest
- 8VoorbeeldGeef het getal terug dat de aanroeper nodig heeft
- 9VoorbeeldStop een uitvoeringspad door voortijdig terug te keren
- 10UitdagingEvalueer van binnen naar buiten
- 11VoorbeeldOnthoud de onvoltooide aanroeper
- 12UitlegGeef recursie een stoppad
- 13VoorbeeldWerk de wachtende vermenigvuldigingen terug af
- 14UitdagingHerstel een recursieve grens
- 15VerbandLees een fout via de stapel
- 16SamenvattingVolg een waarde door elke grens
3Zoek de declaratie achter een naam
10 stappen
Sla deze les op om elke Walkthrough stap voor stap te volgen.
- 1IntroductieVraag je af waar de naam hoort
- 2VoorbeeldVergelijk blok- en functiegrenzen
- 3VoorbeeldGebruik de plaats van de definitie
- 4UitdagingVolg een lokale en een buitenste waarde
- 5UitlegStop bij de dichtstbijzijnde declaratie
- 6KernpuntGeregistreerd is niet hetzelfde als geïnitialiseerd
- 7UitdagingVoorspel wat er gebeurt bij het lezen van een overschaduwde naam
- 8TipHoud hertoewijzing en mutatie uit elkaar
- 9UitdagingCombineer een callback met het moment van opzoeken
- 10SamenvattingVolg eerst de plaats en dan de waarde
4Geef teruggegeven functies een eigen geheugen
11 stappen
Sla deze les op om elke Walkthrough stap voor stap te volgen.
- 1IntroductieBehoud toegang na een return
- 2VoorbeeldMaak een teller zonder die aan te roepen
- 3VoorbeeldWerk de behouden variabele bij
- 4UitdagingVergelijk onafhankelijke tellers
- 5KernpuntBehoud de binding, geen momentopname
- 6VoorbeeldMaak een ingestelde berekening
- 7VoorbeeldHoud een gebruiksteller privé
- 8UitdagingVerklaar drie gelijke resultaten
- 9VerbandHerken privébereik in oudere code
- 10UitdagingDeel één ingestelde bewerking
- 11SamenvattingVolg hoeveel omgevingen er bestaan
5Geef gedrag door en bouw aangepaste functies
15 stappen
Sla deze les op om elke Walkthrough stap voor stap te volgen.
- 1IntroductieLaat een functie het veranderende gedrag leveren
- 2VoorbeeldRoep de meegegeven handeling aan
- 3UitdagingGebruik een callbackresultaat
- 4TipBekijk alle callbackargumenten
- 5VoorbeeldSchrijf een transformatiepatroon
- 6UitlegKies de vorm van het resultaat
- 7UitdagingVolg een selectie en een transformatie
- 8KernpuntKies de numerieke volgorde bewust
- 9VoorbeeldOmhul een aanroep en geef die door
- 10UitlegOnthoud of een aanroep is uitgevoerd
- 11VoorbeeldCombineer functies van binnen naar buiten
- 12VoorbeeldLeg invoer vast vóór de latere aanroep
- 13UitdagingGeef een ingestelde callback door
- 14UitdagingHerstel een verloren resultaat van een omhullende functie
- 15SamenvattingControleer beide stappen van code met hogere-ordefuncties
JavaScript-functies: oefenvragen
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"); }
Toon antwoordVerberg antwoord
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
value die gelijk is aan de invoer n?Toon antwoordVerberg antwoord
{ 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);
Toon antwoordVerberg antwoord
[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";
}
Toon antwoordVerberg antwoord
Vraag 5 van 10
Wat geeft totalDown(3) terug?
function totalDown(n) {
if (n === 0) { return 0; }
return n + totalDown(n - 1);
}
Toon antwoordVerberg antwoord
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";
}
Toon antwoordVerberg antwoord
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();
Toon antwoordVerberg antwoord
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());
Toon antwoordVerberg antwoord
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());
Toon antwoordVerberg antwoord
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));
Toon antwoordVerberg antwoord
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
function showLabel() { console.log("Ready"); }, welke instructie roept de functie aan?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;
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; };
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;
}
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; }
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);
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;
}
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();
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");
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);
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());
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);
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);
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;
}
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;
}
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);
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();
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);
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];
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);
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
function printLine() { console.log("---"); } en voert daarna printline(); uit. Wat gebeurt er?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);
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);
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);
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();
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
}
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();
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);
}
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));
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);
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
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; }
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));
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;
}
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();
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()];
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);
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;
});
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);
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);
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Kom je niet uit je eigen opgave? Huiswerkhulp
Kernbegrippen
A
aanroepspoor
aanroepstapel
sumOfSquares op square(3) wacht, heeft de aanroep van square een frame boven de wachtende aanroeper.accumulator
[5, 10, 15].anonieme functie
function (n) { return n * n; } heeft in de geschreven syntaxis geen interne functienaam.argument
area(4, 2.5) zijn de argumenten 4 en 2,5, ongeacht hoe de parameters zijn genoemd.arguments-object
arguments[0] lezen, maar kan arguments.map niet als gewone arraymethode aanroepen.arraydestructurering
const [low, high] = minMax(values); pakt de twee items van de teruggegeven array uit.B
basisgeval
n <= 1 de aanroepen bij 0 of 1.benoemde functie-expressie
const factorial = function fact(n) { /* body */ }; is factorial de variabele voor buiten de functie en fact de interne naam.bereikketen
amount voordat een variabele met dezelfde naam in een buitenste bereik wordt bekeken.bewakingsclausule
if (b === 0) { return null; } beschermt de deling die erna in safeDivide staat.binding
binding per iteratie
let i kunnen na afloop van de lus verschillende waarden teruggeven.blokbereik
let message die in een if-blok is gedeclareerd, kan niet worden gelezen door een instructie na het einde van dat blok.C
callback
countIf roept voor elk item de testcallback aan en telt de items waarvan het testresultaat truthy is.camelCase
calculateTotal beschrijft een handeling en onderscheidt de twee woorden zonder spaties of underscores.closure
count blijven verhogen nadat de fabriek die haar maakte is beëindigd.D
direct aangeroepen functie-expressie
(function () { var hidden = 1; })(); roepen de zojuist gemaakte functie aan.E
expressie als functielichaam
(a, b) => a + b geeft direct de som van de twee doorgegeven argumenten terug.F
falsy-waarde
level || 50 vervangt 0, terwijl een standaardwaarde van een parameter die doorgegeven waarde behoudt.functie
printHeading("Report") en printHeading("Totals") aan om dezelfde routine voor een kop te hergebruiken.functie-expressie
const square = function (n) { return n * n; }; levert de expressie de waarde die in square wordt opgeslagen.functieaanroep
sayHi() schrijft, wordt het functielichaam uitgevoerd, terwijl een regel met alleen sayHi de functiewaarde leest.functiebereik
var result die in een if-blok een waarde krijgt, kan later vanuit het omvattende functielichaam worden teruggegeven.functiecompositie
f(g(x)) kan een wijziging van de volgorde naar g(f(x)) het resultaat veranderen, ook als beide functies getallen accepteren.functiedeclaratie
greet("Li") kan binnen hetzelfde bereik boven de geschreven declaratie van greet staan.functiefabriek
makeMultiplier(3) geeft een functie terug die 3 onthoudt en later een getal accepteert om mee te vermenigvuldigen.functielichaam
printHeading drie instructies bevat die iets tonen, worden ze alle drie bij elke aanroep van die functie opnieuw uitgevoerd.functiereferentie
const alias = square; roept alias(4) de functie aan die ook via square bereikbaar is.G
gedeelde toestand
balance bereiken.globaal bereik
count op het hoogste niveau van een script kan gedeelde toestand worden wanneer meerdere functies die lezen of bijwerken.H
hertoewijzing
arr = [] de parameter naar iets anders verwijzen zonder de arrayreferentie van de aanroeper te vervangen.hogere-ordefunctie
hoisting
var waarop hoisting is toegepast vóór de toewijzing leest, krijg je undefined; een vroege aanroep van een functiedeclaratie kan worden uitgevoerd.I
inlinefunctie
repeat(3, (i) => console.log(i)) levert de handeling zonder afzonderlijke benoemde declaratie.instructieblok als functielichaam
(n) => { n * 2; } berekent een product maar geeft undefined terug omdat er geen return-instructie is.L
lexicaal bereik
lokale variabele
total gebruiken zonder dat hun optellingen elkaar beïnvloeden.M
methodeketen
mutatie
arr.push(3) aanroept, wijzigt dezelfde array die de aanroeper als argument heeft doorgegeven.N
neveneffect
O
objectliteral
(n) => ({ value: n }) geeft een object terug in plaats van de accolades als een instructieblok te behandelen.omhullende functie
omhullende functie voor eenmalige uitvoering
overschaduwing
count verbergt binnen die functie een buitenste count zonder de buitenste binding te wijzigen.P
parameter
width en height zijn parameters in function area(width, height) { return width * height; }.parameter met een standaardwaarde
level = 50 behoudt een expliciete 0 maar levert 50 wanneer het argument ontbreekt.partiële toepassing
pijlfunctie
(n) => n * 2 levert een korte transformatiecallback aan een arraymethode zoals map.predicaat
(n) => n > 4 selecteert welke getallen een filter behoudt zonder hun waarden zelf te wijzigen.privétoestand
used niet direct toegankelijk is.R
recursie
recursief geval
n * factorial(n - 1) wacht op de kleinere faculteit voordat die met de n van deze aanroep wordt vermenigvuldigd.restparameter
function log(label, ...values) { /* body */ } staat het eerste argument los van de restarray.retourwaarde
double(5) de waarde 10 teruggeeft, kan de expressie double(5) + 1 die waarde direct gebruiken om 11 te maken.S
spreadsyntaxis
Math.max(...[3, 7, 2]) geeft drie getallen door aan Math.max in plaats van één array.stapelframe
n bewaren omdat ze afzonderlijke frames hebben.strikte modus
"use strict";, veroorzaakt een niet-gedeclareerde toewijzing count = 5; een ReferenceError.synchrone callback
T
tijdelijke dode zone
transformatiecallback
(n) => n * n zet de items van [1, 2, 3] via een transformatiebewerking om in kwadraten.U
uitgestelde callback
sayHi aan setTimeout doorgeeft, kunnen de volgende instructies worden uitgevoerd voordat de ingeplande begroeting verschijnt.V
vastgelegde variabele
greeting van “Hi” in “Hello” verandert, verandert de waarde die een latere aanroep van een functie die greeting leest, teruggeeft.vergelijkingsfunctie
(a, b) => a - b sorteert getallen in oplopende volgorde terwijl sort de invoerarray herschikt.voortijdig terugkeren
null teruggeven bij nul als deler voordat de uitvoering de delingsinstructie bereikt.Z
zuivere functie
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.