Closures in JavaScript
Dit artikel legt closures in JavaScript uit.
YouTube Video
Closures in JavaScript
In JavaScript is een 'closure' een van de zeer belangrijke en krachtige concepten. Door closures te begrijpen, kun je kennis opdoen die nuttig is in veel situaties, zoals het gedrag en de scope van functies, evenals de asynchrone verwerking en eventafhandeling in JavaScript. Hier leggen we in detail alles uit, van de basisdefinitie van closures tot concrete voorbeelden en hun toepassingen.
Wat is een Closure?
Een closure verwijst naar het mechanisme waarbij een functie toegang heeft tot variabelen uit de scope waarin hij is aangemaakt, zelfs wanneer hij buiten die scope wordt aangeroepen. Door closures te gebruiken, wordt het mogelijk voor functies om externe variabelen te blijven 'onthouden'.
Closures bestaan uit de volgende twee elementen.
-
Functiedefinitie (de functie zelf)
-
Scope waarin de functie is gedefinieerd (variabelen en andere functies buiten de functie zelf)
In JavaScript zijn closures mogelijk omdat functies toegang hebben tot variabelen binnen de scope waarin ze zijn aangemaakt.
Basisvoorbeeld
Laten we eerst kijken naar een basisvoorbeeld van een closure. In de volgende code retourneert outerFunction
een functie genaamd innerFunction
. Het belangrijke punt is dat innerFunction
toegang heeft tot de variabele count
, die gedefinieerd is in de scope van outerFunction
.
1function outerFunction() {
2 let count = 0;
3
4 function innerFunction() {
5 count++;
6 console.log(`Current count: ${count}`);
7 }
8
9 return innerFunction;
10}
11
12const counter = outerFunction();
13counter(); // Current count: 1
14counter(); // Current count: 2
15counter(); // Current count: 3
Hoe werken Closures
Zoals te zien is in het bovenstaande voorbeeld, wordt count
door innerFunction
vastgehouden, zelfs nadat outerFunction
is uitgevoerd. innerFunction
heeft blijvend toegang tot de scope van outerFunction
, en daarom wordt count
binnen innerFunction
bijgewerkt. Dit is het basismechanisme van een closure.
Het is innerFunction
die wordt toegewezen aan de variabele counter
, en we zien dat de staat van count
behouden blijft, ook al is outerFunction
al uitgevoerd. Dit komt doordat JavaScript voortdurend de scope onthoudt op het moment van functiedefinitie.
Toepassing: Closures als Privé-variabelen
Closures kunnen worden gebruikt als 'privé-variabelen' in objectgeoriënteerd programmeren. Normaal gesproken zijn objecteigenschappen in JavaScript direct toegankelijk van buitenaf, maar door closures te gebruiken, kun je directe manipulatie van variabelen binnen de functie-scope van buitenaf voorkomen.
In het volgende voorbeeld gebruikt de functie createCounter
een closure om een teller te maken en retourneert een teller met een privévariabele count
.
1function createCounter() {
2 let count = 0;
3
4 return {
5 increment: function() {
6 count++;
7 console.log(`Count: ${count}`);
8 },
9 decrement: function() {
10 count--;
11 console.log(`Count: ${count}`);
12 },
13 getCount: function() {
14 return count;
15 }
16 };
17}
18
19const myCounter = createCounter();
20myCounter.increment(); // Count: 1
21myCounter.increment(); // Count: 2
22myCounter.decrement(); // Count: 1
23console.log(myCounter.getCount()); // 1
In dit voorbeeld bevindt count
zich in de scope van de functie createCounter
, waardoor er niet direct van buitenaf toegang toe is. Het kan echter worden gemanipuleerd via de methoden increment
en decrement
. Op deze manier kun je met closures het concept van privé-variabelen in JavaScript toepassen.
Praktische Voorbeelden van Closures
Combinatie met Callback-functies
Closures worden vaak gebruikt in combinatie met callback-functies om asynchrone processen te beheren. Laten we bijvoorbeeld eens kijken naar een voorbeeld met een timer.
1function startTimer(duration) {
2 let timeLeft = duration;
3
4 function countdown() {
5 console.log(`Time left: ${timeLeft} seconds`);
6 timeLeft--;
7
8 if (timeLeft >= 0) {
9 setTimeout(countdown, 1000);
10 }
11 }
12
13 countdown();
14}
15
16startTimer(5);
17// Time left: 5 seconds
18// Time left: 4 seconds
19// Time left: 3 seconds
20// Time left: 2 seconds
21// Time left: 1 second
22// Time left: 0 seconds
In dit voorbeeld krijgt de functie countdown
toegang tot de variabele timeLeft
binnen de scope van startTimer
. Op deze manier zijn closures erg handig voor asynchrone processen zoals timers, omdat ze de status van variabelen over tijd behouden.
Eventhandlers
Closures zijn ook handig bij het opzetten van eventhandlers. In het volgende voorbeeld wordt een closure gebruikt om het aantal keer dat op een knop is geklikt bij te houden.
1function setupClickCounter(buttonId) {
2 let clickCount = 0;
3
4 const button = document.getElementById(buttonId);
5 button.addEventListener('click', function() {
6 clickCount++;
7 console.log(`Button clicked ${clickCount} times`);
8 });
9}
10
11setupClickCounter('myButton');
In dit geval neemt clickCount
toe bij elke klik en wordt de waarde ervan behouden. Met closures kun je elke knop een aparte teller geven.
Conclusie
Closures zijn een concept dat de flexibiliteit en kracht van JavaScript symboliseert. Ze bewaren variabelen binnen een functiescope en maken bewerkingen op die variabelen mogelijk via extern toegankelijke functies. Door dit mechanisme te begrijpen en te gebruiken, kun je geavanceerdere technieken in JavaScript ontwikkelen.
Closures worden in verschillende situaties toegepast, van eventafhandeling en asynchrone verwerking tot zelfs pseudo-implementaties van objectgeoriënteerd programmeren.
Je kunt het bovenstaande artikel volgen met Visual Studio Code op ons YouTube-kanaal. Bekijk ook het YouTube-kanaal.