Een eenvoudige gids om u te helpen sluitingen in JavaScript te begrijpen

Sluitingen in JavaScript zijn een van die concepten waar velen moeite mee hebben om hun hoofd rond te krijgen. In het volgende artikel zal ik in duidelijke bewoordingen uitleggen wat een sluiting is, en ik zal het punt naar huis brengen met behulp van eenvoudige codevoorbeelden.

Wat is een sluiting?

Een sluiting is een functie in JavaScript waarbij een binnenfunctie toegang heeft tot de variabelen van de buitenste (omhullende) functie - een scoopketen.

De sluiting heeft drie scoopkettingen:

  • het heeft toegang tot zijn eigen bereik - variabelen gedefinieerd tussen de accolades
  • het heeft toegang tot de variabelen van de externe functie
  • het heeft toegang tot de globale variabelen

Voor niet-ingewijden lijkt deze definitie misschien gewoon heel veel jargon!

Maar wat is echt een sluiting?

Een eenvoudige sluiting

Laten we eens kijken naar een eenvoudig afsluitingsvoorbeeld in JavaScript:

function outer () {
   var b = 10;
   function inner () {
        
         var a = 20;
         console.log (a + b);
    }
   terugkeer innerlijk;
}

Hier hebben we twee functies:

  • een buitenste functie buiten die een variabele b heeft en de binnenste functie retourneert
  • een innerlijke functie innerlijk waarvan de variabele a wordt genoemd, en toegang heeft tot een buitenste variabele b, binnen zijn functielichaam

Het bereik van variabele b is beperkt tot de buitenste functie en het bereik van variabele a is beperkt tot de binnenste functie.

Laten we nu de functie outer () aanroepen en het resultaat van de functie outer () opslaan in een variabele X. Laten we de functie outer () een tweede keer aanroepen en opslaan in variabele Y.

function outer () {
   var b = 10;
   function inner () {
        
         var a = 20;
         console.log (a + b);
    }
   terugkeer innerlijk;
}
var X = buiten (); // outer () de eerste keer aangeroepen
var Y = buiten (); // outer () voor de tweede keer aangeroepen

Laten we stap voor stap zien wat er gebeurt wanneer de functie outer () voor het eerst wordt aangeroepen:

  1. Variabele b is gemaakt, het bereik is beperkt tot de functie outer () en de waarde is ingesteld op 10.
  2. De volgende regel is een functieverklaring, dus niets om uit te voeren.
  3. Op de laatste regel zoekt return inner naar een variabele met de naam inner, vindt dat deze variabele inner in feite een functie is, en geeft dus het hele lichaam van de functie inner terug.
    [Merk op dat de return-opdracht niet de innerlijke functie uitvoert - een functie wordt alleen uitgevoerd wanneer gevolgd door () -, maar de return-opdracht retourneert de volledige hoofdtekst van de functie.]
  4. De inhoud die wordt geretourneerd door de retourverklaring wordt opgeslagen in X.
    Dus zal X het volgende opslaan:
     function inner () {
     var a = 20;
    console.log (a + b);
    }
  5. De functie outer () voltooit de uitvoering en alle variabelen binnen het bereik van outer () bestaan ​​nu niet meer.

Dit laatste deel is belangrijk om te begrijpen. Als een functie eenmaal is uitgevoerd, houden alle variabelen die binnen het functiebereik waren gedefinieerd op te bestaan.

De levensduur van een variabele die binnen een functie wordt gedefinieerd, is de levensduur van de functie-uitvoering.

Dit betekent dat in console.log (a + b) de variabele b alleen bestaat tijdens de uitvoering van de functie outer (). Als de buitenfunctie eenmaal is voltooid, bestaat de variabele b niet meer.

Wanneer de functie de tweede keer wordt uitgevoerd, worden de variabelen van de functie opnieuw gemaakt en worden deze pas live totdat de functie is voltooid.

Dus wanneer outer () de tweede keer wordt aangeroepen:

  1. Er wordt een nieuwe variabele b gemaakt, het bereik is beperkt tot de functie outer () en de waarde is ingesteld op 10.
  2. De volgende regel is een functieverklaring, dus niets om uit te voeren.
  3. return inner retourneert het hele lichaam van de innerlijke functie.
  4. De inhoud die wordt geretourneerd door de retourverklaring wordt opgeslagen in Y.
  5. De functie outer () voltooit de uitvoering en alle variabelen binnen het bereik van outer () bestaan ​​nu niet meer.

Het belangrijke punt hier is dat wanneer de functie outer () voor de tweede keer wordt aangeroepen, de variabele b opnieuw wordt gemaakt. Ook wanneer de functie outer () de tweede keer wordt uitgevoerd, houdt deze nieuwe variabele b weer op te bestaan.

Dit is het belangrijkste te realiseren punt. De variabelen binnen de functies ontstaan ​​alleen wanneer de functie actief is en houden op te bestaan ​​zodra de functies zijn voltooid.

Laten we nu terugkeren naar ons codevoorbeeld en kijken naar X en Y. Aangezien de functie outer () bij uitvoering een functie retourneert, zijn de variabelen X en Y functies.

Dit kan eenvoudig worden geverifieerd door het volgende toe te voegen aan de JavaScript-code:

console.log (typeof (X)); // X is van het type functie
console.log (typeof (Y)); // Y is van het type functie

Omdat de variabelen X en Y functies zijn, kunnen we ze uitvoeren. In JavaScript kan een functie worden uitgevoerd door () toe te voegen na de functienaam, zoals X () en Y ().

function outer () {
var b = 10;
   function inner () {
        
         var a = 20;
         console.log (a + b);
    }
   terugkeer innerlijk;
}
var X = buiten ();
var Y = buiten ();
// einde van outer () functie-uitvoeringen
X(); // X () de eerste keer aangeroepen
X(); // X () voor de tweede keer aangeroepen
X(); // X () voor de derde keer aangeroepen
Y (); // Y () de eerste keer aangeroepen

Wanneer we X () en Y () uitvoeren, voeren we in wezen de innerlijke functie uit.

Laten we stap voor stap onderzoeken wat er gebeurt wanneer X () de eerste keer wordt uitgevoerd:

  1. Variabele a wordt gemaakt en de waarde ervan is ingesteld op 20.
  2. JavaScript probeert nu a + b uit te voeren. Hier wordt het interessant. JavaScript weet dat er een bestaat sinds het net is gemaakt. Variabele b bestaat echter niet meer. Omdat b deel uitmaakt van de buitenste functie, zou b alleen bestaan ​​terwijl de outer () functie wordt uitgevoerd. Aangezien de functie outer () lang voordat de X () werd aangeroepen, de uitvoering beëindigde, houden alle variabelen binnen het bereik van de externe functie op te bestaan, en daarom bestaat variabele b niet meer.

Hoe gaat JavaScript hiermee om?

sluitingen

De binnenfunctie heeft toegang tot de variabelen van de omhullende functie vanwege sluitingen in JavaScript. Met andere woorden, de binnenfunctie behoudt de scoopketen van de omhullende functie op het moment dat de omhullende functie werd uitgevoerd, en kan dus toegang krijgen tot de variabelen van de omhullende functie.

In ons voorbeeld had de innerlijke functie de waarde van b = 10 behouden toen de outer () -functie werd uitgevoerd, en bleef deze behouden (sluiten).

Het verwijst nu naar zijn scoopketen en merkt op dat het wel de waarde van variabele b binnen de scoopketen heeft, omdat het de waarde van b binnen een afsluiting had ingesloten op het moment dat de externe functie was uitgevoerd.

JavaScript kent dus a = 20 en b = 10 en kan a + b berekenen.

U kunt dit verifiëren door de volgende coderegel toe te voegen aan het bovenstaande voorbeeld:

function outer () {
var b = 10;
   function inner () {
        
         var a = 20;
         console.log (a + b);
    }
   terugkeer innerlijk;
}
var X = buiten ();
console.dir (X); // gebruik console.dir () in plaats van console.log ()

Open het Inspect-element in Google Chrome en ga naar de console. U kunt het element uitbreiden om het element Closure te zien (weergegeven in de derde tot laatste regel hieronder). Merk op dat de waarde van b = 10 behouden blijft in de sluiting, zelfs nadat de functie outer () de uitvoering ervan heeft voltooid.

Variabele b = 10 wordt bewaard in de sluiting, sluitingen in Javascript

Laten we nu de definitie van sluitingen die we in het begin zagen opnieuw bekijken en kijken of het nu logischer is.

De innerlijke functie heeft dus drie scoopketens:

  • toegang tot zijn eigen toepassingsgebied - variabele a
  • toegang tot de variabelen van de buitenste functie - variabele b, die deze heeft ingesloten
  • toegang tot alle globale variabelen die kunnen worden gedefinieerd

Sluitingen in actie

Om het sluitingspunt naar huis te rijden, laten we het voorbeeld aanvullen met drie coderegels:

function outer () {
var b = 10;
var c = 100;
   function inner () {
        
         var a = 20;
         console.log ("a =" + a + "b =" + b);
         a ++;
         b ++;
    }
   terugkeer innerlijk;
}
var X = buiten (); // outer () de eerste keer aangeroepen
var Y = buiten (); // outer () voor de tweede keer aangeroepen
// einde van outer () functie-uitvoeringen
X(); // X () de eerste keer aangeroepen
X(); // X () voor de tweede keer aangeroepen
X(); // X () voor de derde keer aangeroepen
Y (); // Y () de eerste keer aangeroepen

Wanneer u deze code uitvoert, ziet u de volgende uitvoer in de console.log:

a = 20 b = 10
a = 20 b = 11
a = 20 b = 12
a = 20 b = 10

Laten we deze code stap voor stap bekijken om te zien wat er precies gebeurt en om sluitingen in actie te zien!

var X = buiten (); // outer () de eerste keer aangeroepen

De functie outer () wordt de eerste keer aangeroepen. De volgende stappen vinden plaats:

  1. Variabele b is gemaakt en is ingesteld op 10
    Variabele c is gemaakt en ingesteld op 100
    Laten we dit b (first_time) en c (first_time) noemen voor onze eigen referentie.
  2. De innerlijke functie wordt geretourneerd en toegewezen aan X
    Op dit punt is de variabele b ingesloten binnen de scope van de interne functieketen als een sluiting met b = 10, omdat inner de variabele b gebruikt.
  3. De uiterlijke functie voltooit de uitvoering en al zijn variabelen houden op te bestaan. De variabele c bestaat niet meer, hoewel de variabele b bestaat als een sluiting binnenin.
var Y = buiten (); // outer () voor de tweede keer aangeroepen
  1. Variabele b wordt opnieuw gemaakt en ingesteld op 10
    Variabele c wordt opnieuw gemaakt.
    Merk op dat hoewel outer () eenmaal werd uitgevoerd voordat de variabelen b en c ophielden te bestaan, ze na de uitvoering van de functie zijn aangemaakt als nieuwe variabelen.
    Laten we deze b (second_time) en c (second_time) noemen voor onze eigen referentie.
  2. De innerlijke functie wordt geretourneerd en toegewezen aan Y
    Op dit punt is de variabele b ingesloten in de binnenste scoopketen als een afsluiting met b (second_time) = 10, omdat inner de variabele b gebruikt.
  3. De uiterlijke functie voltooit de uitvoering en al zijn variabelen houden op te bestaan.
    De variabele c (second_time) bestaat niet meer, hoewel de variabele b (second_time) bestaat als afsluiting binnenin.

Laten we nu eens kijken wat er gebeurt wanneer de volgende regels code worden uitgevoerd:

X(); // X () de eerste keer aangeroepen
X(); // X () voor de tweede keer aangeroepen
X(); // X () voor de derde keer aangeroepen
Y (); // Y () de eerste keer aangeroepen

Wanneer X () de eerste keer wordt aangeroepen,

  1. variabele a wordt gemaakt en ingesteld op 20
  2. de waarde van a = 20, de waarde van b is van de sluitingswaarde. b (eerste_tijd), dus b = 10
  3. variabelen a en b worden met 1 verhoogd
  4. X () voltooit de uitvoering en al zijn innerlijke variabelen - variabele a - houden op te bestaan.
    B (first_time) bleef echter behouden als de afsluiting, dus b (first_time) blijft bestaan.

Wanneer X () de tweede keer wordt aangeroepen,

  1. variabele a wordt opnieuw gemaakt en ingesteld op 20
     Elke eerdere waarde van variabele a bestaat niet meer, omdat deze ophield te bestaan ​​toen X () de eerste keer de uitvoering voltooide.
  2. de waarde van a = 20
    de waarde van b wordt genomen van de sluitingswaarde - b (first_time)
    Merk ook op dat we de waarde van b met 1 hadden verhoogd van de vorige uitvoering, dus b = 11
  3. variabelen a en b worden weer met 1 verhoogd
  4. X () voltooit de uitvoering en al zijn innerlijke variabelen - variabele a - houden op te bestaan
    B (first_time) blijft echter behouden terwijl de sluiting blijft bestaan.

Wanneer X () voor de derde keer wordt aangeroepen,

  1. variabele a wordt opnieuw gemaakt en ingesteld op 20
    Elke eerdere waarde van variabele a bestaat niet meer, omdat deze ophield te bestaan ​​toen X () de eerste keer de uitvoering voltooide.
  2. de waarde van a = 20, de waarde van b is van de sluitingswaarde - b (first_time)
    Merk ook op dat we de waarde van b met 1 hadden verhoogd in de vorige uitvoering, dus b = 12
  3. variabelen a en b worden weer met 1 verhoogd
  4. X () voltooit de uitvoering en alle innerlijke variabelen - variabele a - houden op te bestaan
    B (first_time) blijft echter behouden terwijl de sluiting blijft bestaan

Wanneer Y () de eerste keer wordt aangeroepen,

  1. variabele a wordt opnieuw gemaakt en ingesteld op 20
  2. de waarde van a = 20, de waarde van b komt van de sluitingswaarde - b (second_time), dus b = 10
  3. variabelen a en b worden met 1 verhoogd
  4. Y () voltooit de uitvoering en alle innerlijke variabelen - variabele a - houden op te bestaan
    B (second_time) bleef echter behouden als de afsluiting, dus b (second_time) blijft bestaan.

Slotopmerkingen

Sluitingen zijn een van die subtiele concepten in JavaScript die in het begin moeilijk te begrijpen zijn. Maar als je ze eenmaal begrijpt, realiseer je je dat het niet anders kon.

Hopelijk hebben deze stapsgewijze uitleg je echt geholpen het begrip sluitingen in JavaScript te begrijpen!

Andere artikelen:

  • Een korte handleiding voor "zelfoproepende" functies in Javascript
  • Functiebereik versus blokbereik in Javascript begrijpen
  • Hoe Promises in JavaScript te gebruiken
  • Hoe een eenvoudige Sprite-animatie in JavaScript te bouwen