En enkel guide til at hjælpe dig med at forstå lukninger i JavaScript

Lukninger i JavaScript er et af de begreber, som mange kæmper for at få deres hoveder rundt. I den følgende artikel vil jeg forklare i klare udtryk, hvad en lukning er, og jeg kører punktet hjem ved hjælp af enkle kodeeksempler.

Hvad er en lukning?

En lukning er en funktion i JavaScript, hvor en indre funktion har adgang til den ydre (lukkende) funktions variabler - en omfangskæde.

Lukningen har tre omfangskæder:

  • det har adgang til sit eget omfang - variabler defineret mellem dets krøllede parenteser
  • det har adgang til den ydre funktions variabler
  • det har adgang til de globale variabler

For de uindviede kan denne definition virke som bare en hel masse jargon!

Men hvad er egentlig en lukning?

En enkel lukning

Lad os se på et simpelt lukningseksempel i JavaScript:

funktion ydre () {
   var b = 10;
   funktion indre () {
        
         var a = 20;
         console.log (a + b);
    }
   vende tilbage indre;
}

Her har vi to funktioner:

  • en ydre funktion ydre, der har en variabel b, og returnerer den indre funktion
  • en indre funktion indre, som har sin variabel kaldet a, og får adgang til en ydre variabel b, inden i dens funktionslegeme

Omfanget af variabel b er begrænset til den ydre funktion, og omfanget af variabel a er begrænset til den indre funktion.

Lad os nu påkalde den ydre () -funktion, og gemme resultatet af den ydre () -funktion i en variabel X. Lad os derefter påberope den ydre () -funktion en anden gang og gemme den i variabel Y.

funktion ydre () {
   var b = 10;
   funktion indre () {
        
         var a = 20;
         console.log (a + b);
    }
   vende tilbage indre;
}
var X = ydre (); // ydre () påberåbte første gang
var Y = ydre (); // ydre () påberåbte anden gang

Lad os se trinvis, hvad der sker, når den ydre () -funktion først påberåbes:

  1. Variabel b oprettes, dens omfang er begrænset til den ydre () -funktion, og dens værdi er indstillet til 10.
  2. Den næste linje er en funktionserklæring, så intet at udføre.
  3. På den sidste linje ser det indre tilbage efter en variabel kaldet indre, finder ud af, at denne variable indre faktisk er en funktion, og således returnerer hele kroppen af ​​funktionen indre.
    [Bemærk, at return-erklæringen ikke udfører den indre funktion - en funktion udføres kun, når den følges af () -, men snarere returnerer return-sætningen hele funktionen.
  4. Indholdet, der returneres af returneringsopgørelsen, gemmes i X.
    Således lagrer X følgende:
     funktion indre () {
     var a = 20;
    console.log (a + b);
    }
  5. Funktion ydre () afslutter udførelsen, og alle variabler inden for rammerne af ydre () findes nu ikke længere.

Denne sidste del er vigtig at forstå. Når en funktion er afsluttet udførelsen, ophører alle variabler, der blev defineret inden for funktionsomfanget.

Levetiden for en variabel defineret inde i en funktion er levetiden for udførelsen af ​​funktionen.

Hvad dette betyder er, at i console.log (a + b) findes variablen b kun under udførelsen af ​​den ydre () -funktion. Når den ydre funktion er afsluttet, eksisterer variablen b ikke længere.

Når funktionen udføres anden gang, oprettes variablerne i funktionen igen og lever kun op, indtil funktionen afslutter udførelsen.

Når ydre () påberåbes anden gang:

  1. Der oprettes en ny variabel b, dens omfang er begrænset til den ydre () -funktion, og dens værdi er indstillet til 10.
  2. Den næste linje er en funktionserklæring, så intet at udføre.
  3. retur indre returnerer hele kroppen til funktionen indre.
  4. Indholdet, der returneres af returneringsopgørelsen, gemmes i Y.
  5. Funktion ydre () afslutter udførelsen, og alle variabler inden for rammerne af ydre () findes nu ikke længere.

Det vigtige punkt her er, at når den ydre () -funktion aktiveres anden gang, oprettes variablen b på ny. Når den ydre () -funktion afslutter udførelsen anden gang, ophører denne nye variabel b igen med at eksistere.

Dette er det vigtigste punkt at indse. Variablerne inde i funktionerne opstår først, når funktionen kører, og ophører med at eksistere, når funktionerne er afsluttet udførelsen.

Lad os nu vende tilbage til vores kodeeksempel og se på X og Y. Da den ydre () -funktion ved udførelse returnerer en funktion, er variablerne X og Y funktioner.

Dette kan let verificeres ved at føje følgende til JavaScript-koden:

console.log (typeof (X)); // X er af typen funktion
console.log (typeof (Y)); // Y er af typen funktion

Da variablerne X og Y er funktioner, kan vi udføre dem. I JavaScript kan en funktion udføres ved at tilføje () efter funktionsnavnet, såsom X () og Y ().

funktion ydre () {
var b = 10;
   funktion indre () {
        
         var a = 20;
         console.log (a + b);
    }
   vende tilbage indre;
}
var X = ydre ();
var Y = ydre ();
// slutningen af ​​ydre () udførelsesfunktioner
X(); // X () påberåbte første gang
X(); // X () påberåbte anden gang
X(); // X () påberåbte tredje gang
Y (); // Y () påberåbte første gang

Når vi udfører X () og Y (), udfører vi i det væsentlige den indre funktion.

Lad os undersøge trin for trin, hvad der sker, når X () udføres første gang:

  1. Variabel a oprettes, og dens værdi er indstillet til 20.
  2. JavaScript forsøger nu at udføre a + b. Her bliver tingene spændende. JavaScript ved, at der findes en, da den netop har oprettet den. Variabel b findes imidlertid ikke længere. Da b er en del af den ydre funktion, ville b kun findes, mens den ydre () -funktion er i udførelse. Da den ydre () -funktion var færdig med eksekveringen længe før vi påkaldte X (), ophører eventuelle variabler inden for omfanget af den ydre funktion og eksisterer derfor ikke længere b.

Hvordan håndterer JavaScript dette?

lukninger

Den indre funktion kan få adgang til variablerne i den lukkende funktion på grund af lukninger i JavaScript. Med andre ord, den indre funktion bevarer omfangskæden for den lukkende funktion på det tidspunkt, hvor den lukkende funktion blev udført, og har således adgang til den lukkende funktions variabler.

I vores eksempel havde den indre funktion bevaret værdien af ​​b = 10, når den ydre () funktion blev udført, og fortsatte med at bevare (lukke) den.

Den henviser nu til dens omfangskæde og bemærker, at den har værdien af ​​variabel b inden for dens omfangskæde, da den havde lukket værdien af ​​b inden i en lukning på det tidspunkt, hvor den ydre funktion var udført.

Således kender JavaScript a = 20 og b = 10 og kan beregne a + b.

Du kan bekræfte dette ved at tilføje følgende kodelinje til eksemplet ovenfor:

funktion ydre () {
var b = 10;
   funktion indre () {
        
         var a = 20;
         console.log (a + b);
    }
   vende tilbage indre;
}
var X = ydre ();
console.dir (X); // brug console.dir () i stedet for console.log ()

Åbn Inspect-elementet i Google Chrome og gå til konsollen. Du kan udvide elementet til faktisk at se lukkeelementet (vist på den tredje til sidste linje nedenfor). Bemærk, at værdien af ​​b = 10 bevares i lukningen, selv efter at den ydre () -funktion har afsluttet dens udførelse.

Variabel b = 10 er bevaret i lukningen, lukninger i Javascript

Lad os nu gennemgå definitionen på lukninger, som vi så i starten, og se, om det nu giver mere mening.

Så den indre funktion har tre omfangskæder:

  • adgang til sit eget omfang - variabel a
  • adgang til den ydre funktions variabler - variabel b, som den lukkede
  • adgang til alle globale variabler, der kan defineres

Lukninger i aktion

For at køre hjemmet til lukningspunktet, lad os øge eksemplet ved at tilføje tre kodelinjer:

funktion ydre () {
var b = 10;
var c = 100;
   funktion indre () {
        
         var a = 20;
         console.log ("a =" + a + "b =" + b);
         a ++;
         b ++;
    }
   vende tilbage indre;
}
var X = ydre (); // ydre () påberåbte første gang
var Y = ydre (); // ydre () påberåbte anden gang
// slutningen af ​​ydre () udførelsesfunktioner
X(); // X () påberåbte første gang
X(); // X () påberåbte anden gang
X(); // X () påberåbte tredje gang
Y (); // Y () påberåbte første gang

Når du kører denne kode, vil du se følgende output i console.log:

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

Lad os undersøge denne kode trin for trin for at se, hvad der nøjagtigt sker, og for at se lukninger i Action!

var X = ydre (); // ydre () påberåbte første gang

Funktionen ydre () aktiveres første gang. Følgende trin finder sted:

  1. Variabel b oprettes og er indstillet til 10
    Variabel c oprettes og indstilles til 100
    Lad os kalde dette b (first_time) og c (first_time) til vores egen reference.
  2. Den indre funktion returneres og tildeles X
    På dette tidspunkt er variablen b lukket inden for den indre funktionskædekæde som en lukning med b = 10, da indre bruger variablen b.
  3. Den ydre funktion afslutter udførelsen, og alle dens variabler ophører med at eksistere. Variablen c eksisterer ikke længere, selvom variablen b eksisterer som en lukning indeni det indre.
var Y = ydre (); // ydre () påberåbte anden gang
  1. Variabel b oprettes på ny og er indstillet til 10
    Variabel c oprettes på ny.
    Bemærk, at selvom ydre () blev udført en gang, før variablerne b og ophørte med at eksistere, oprettes de, når funktionen var afsluttet, som splinternye variabler.
    Lad os kalde disse b (second_time) og c (second_time) til vores egen reference.
  2. Den indre funktion returneres og tildeles Y
    På dette tidspunkt er variablen b lukket inden for den indre funktionskædekæde som en lukning med b (second_time) = 10, da indre bruger variablen b.
  3. Den ydre funktion afslutter udførelsen, og alle dens variabler ophører med at eksistere.
    Variablen c (second_time) eksisterer ikke længere, selvom variablen b (second_time) eksisterer som lukning inden i det indre.

Lad os nu se, hvad der sker, når de følgende kodelinjer udføres:

X(); // X () påberåbte første gang
X(); // X () påberåbte anden gang
X(); // X () påberåbte tredje gang
Y (); // Y () påberåbte første gang

Når X () kaldes første gang,

  1. variabel a oprettes og indstilles til 20
  2. værdien af ​​a = 20, værdien af ​​b er fra lukkeværdien. b (first_time), så b = 10
  3. variabler a og b forøges med 1
  4. X () afslutter eksekveringen og alle dens indre variabler - variabel - ophører med at eksistere.
    Dog blev b (first_time) bevaret som lukningen, så b (first_time) fortsætter med at eksistere.

Når X () påberåbes anden gang,

  1. variabel a oprettes på ny og indstilles til 20
     Enhver tidligere værdi af variabel a eksisterer ikke længere, da den ophørte med at eksistere, når X () afsluttede udførelsen første gang.
  2. værdien af ​​a = 20
    værdien af ​​b er hentet fra lukkeværdien - b (første gang)
    Bemærk også, at vi havde øget værdien af ​​b med 1 fra den forrige udførelse, så b = 11
  3. variablerne a og b øges med 1 igen
  4. X () afslutter eksekveringen og alle dens indre variabler - variabel - ophører med at eksistere
    Dog er b (first_time) bevaret, når lukningen fortsætter med at eksistere.

Når X () påberåbes for tredje gang,

  1. variabel a oprettes på ny og indstilles til 20
    Enhver tidligere værdi af variabel a eksisterer ikke længere, da den ophørte med at eksistere, da X () afsluttede udførelsen første gang.
  2. værdien af ​​a = 20, værdien af ​​b er fra lukkeværdien - b (første gang)
    Bemærk også, at vi havde forøget værdien af ​​b med 1 i den forrige udførelse, så b = 12
  3. variablerne a og b øges med 1 igen
  4. X () afslutter udførelsen, og alle dens indre variabler - variabel a - ophører med at eksistere
    Dog er b (first_time) bevaret, når lukningen fortsætter med at eksistere

Når Y () kaldes første gang,

  1. variabel a oprettes på ny og indstilles til 20
  2. værdien af ​​a = 20, værdien af ​​b er fra lukkeværdien - b (second_time), så b = 10
  3. variabler a og b forøges med 1
  4. Y () afslutter udførelsen, og alle dens indre variabler - variabel a - ophører med at eksistere
    Dog blev b (second_time) bevaret som lukningen, så b (second_time) fortsætter med at eksistere.

Afsluttende bemærkninger

Lukninger er et af disse subtile koncepter i JavaScript, der først er vanskelige at forstå. Men når du først har forstået dem, er du klar over, at tingene ikke kunne have været nogen anden måde.

Forhåbentlig hjalp disse trinvise forklaringer dig virkelig til at forstå begrebet lukninger i JavaScript!

Andre artikler:

  • En hurtig guide til “selvangivende” funktioner i Javascript
  • Forståelse af funktionsomfang kontra blokeringsomfang i Javascript
  • Sådan bruges løfter i JavaScript
  • Sådan bygger du en simpel Sprite-animation i JavaScript