border=0

"77.95.5.4 - 77.95.5.4"

Hoe werken Javascript-blokkers?

Hoe zou u de sluiting van JavaScript verklaren voor iemand die kennis heeft van de concepten waaruit zij zijn samengesteld (bijvoorbeeld functies, variabelen, enz.), Maar de sluitingen zelf niet begrijpt?

Ik zag een voorbeeld van het schema op Wikipedia, maar helaas hielp het niet.

7654
21 сент. ingesteld op e satis op 21 sept. 2008-09-21 17:12 '08 om 17:12 uur 2008-09-21 17:12
@ 89 antwoorden
  • 1
  • 2
  • 3

Sluit javascript voor beginners

Ingezonden door Morris op di, 2006-02-21 10:19. De community is sindsdien bewerkt.

Sluiten is geen magie

Deze pagina legt de sluiting uit, zodat de programmeur ze kan begrijpen - met behulp van werkende JavaScript-code. Dit is niet voor goeroes of functionele programmeurs.

De sluiting is niet moeilijk te begrijpen zodra het basisconcept is bekabeld. Ze kunnen echter niet worden begrepen door het lezen van theoretische of academisch gebaseerde verklaringen!

Dit artikel is bedoeld voor programmeurs met enige basiservaring met programmeren en kan de volgende JavaScript-functie lezen:

topfuncties te ondersteunen;  is een uitdrukking die kan verwijzen naar variabelen binnen de scope (wanneer deze eerder is gedeclareerd), wordt toegewezen aan een variabele, wordt doorgegeven als een functieargument of wordt geretourneerd als het resultaat van een functie. 

Afsluitend voorbeeld

De volgende code levert een functie-verwijzing op:

 function say667() { // Local variable that ends up within closure var num = 42; var say = function() { console.log(num); } num++; return say; } var sayNumber = say667(); sayNumber(); // logs 43 

Voorbeeld 4

Alle drie de globale functies hebben dezelfde verwijzing naar dezelfde close, omdat ze allemaal worden gedeclareerd tijdens een enkele aanroep van setupSomeGlobals() .

Merk op dat in het bovenstaande voorbeeld, als u setupSomeGlobals() opnieuw setupSomeGlobals() , er een nieuwe afsluiting wordt gemaakt (stack-frame!). Oud gLogNumber , gIncreaseNumber , gSetNumber overschreven door nieuwe functies die een nieuwe afsluiting hebben. (In JavaScript, wanneer u een functie binnen een andere functie declareert, worden interne functies opnieuw aangemaakt telkens wanneer een externe functie wordt aangeroepen.)

Voorbeeld 5

Dit voorbeeld laat zien dat de afsluiting lokale variabelen bevat die zijn gedeclareerd in een externe functie voordat deze werd afgesloten. Merk op dat de alice variabele feitelijk wordt gedeclareerd na de anonieme functie. De anonieme functie wordt eerst gedeclareerd en wanneer deze functie wordt aangeroepen, heeft deze toegang tot de alice variabele, omdat alice zich in hetzelfde gebied bevindt (JavaScript, maakt variabelen Lifter ). Ook sayAlice()() gewoon de functie sayAlice() , geretourneerd door sayAlice() is exact hetzelfde als hiervoor, maar zonder een tijdelijke variabele.

 function buildList(list) { var result = []; for (var i = 0; i < list.length; i++) { var item = 'item' + i; result.push( function() {console.log(item + ' ' + list[i])} ); } return result; } function testList() { var fnlist = buildList([1,2,3]); // Using j only to help prevent confusion -- could use i. for (var j = 0; j < fnlist.length; j++) { fnlist[j](); } } testList() //logs "item2 undefined" 3 times 

De tekenreeks result.push( function() {console.log(item + ' ' + list[i])} voegt driemaal een anonieme functieverwijzing toe aan de resultatenmatrix.Als u niet vertrouwd bent met anonieme functies, zoals deze:

 pointer = function() {console.log(item + ' ' + list[i])}; result.push(pointer); 

Let op: als u het voorbeeld uitvoert, wordt "item2 undefined" drie keer geschreven! Dit is het gevolg van het feit dat, net als in de vorige voorbeelden, er slechts één afsluiting is voor lokale variabelen voor buildList ( result , i en item ). Wanneer anonieme functies fnlist[j]() aanroepen; ze gebruiken allemaal dezelfde enkele afsluiting en ze gebruiken de huidige waarde voor i en item binnen één afsluiting (waarbij i waarde 3 omdat de cyclus is voltooid en item waarde 'item2' ). Merk op dat we indexeren vanaf 0, dus item heeft de waarde item2 . En i ++ verhoogt i naar een waarde van 3 .

Dit kan handig zijn om te zien wat er gebeurt wanneer de declaratie op blokniveau van de artikelvariabele wordt gebruikt (via het let sleutelwoord) in plaats van een functie in bereik van het declareren van een variabele via het var sleutelwoord. Als deze wijziging wordt aangebracht, heeft elke anonieme functie in de result de sluiting; Bij het uitvoeren van het voorbeeld is de uitvoer als volgt:

 item0 undefined item1 undefined item2 undefined 

Als de variabele i ook wordt gedefinieerd met behulp van let plaats van var , dan is de uitvoer:

 item0 1 item1 2 item2 3 

Voorbeeld 7

In dit laatste voorbeeld maakt elke aanroep van de hoofdfunctie een afzonderlijke afsluiting.

functieconstructor ) in een functie gebruikt, maakt deze geen close.  (De nieuwe functie kan niet verwijzen naar lokale variabelen van de externe functie.) 
  • Het sluiten van JavaScript lijkt op het opslaan van een kopie van alle lokale variabelen, net als wanneer u een functie afsluit.
  • Het is waarschijnlijk het beste om te denken dat de sluiting altijd wordt gemaakt als een functie-invoer en dat lokale variabelen aan deze sluiting worden toegevoegd.
  • Elke keer dat een functie met een afsluiting wordt aangeroepen, wordt een nieuwe set lokale variabelen opgeslagen (aangezien de functie daarin een functiedeclaratie bevat, wordt de verwijzing naar deze interne functie ofwel geretourneerd of de externe referentie wordt er op een of andere manier voor opgeslagen).
  • Twee functies kunnen eruit zien alsof ze dezelfde broncode hebben, maar hebben volledig ander gedrag vanwege hun verborgen sluiting. Ik denk niet dat de JavaScript-code echt kan achterhalen of de functie een link-sluiting heeft of niet.
  • Als u probeert de dynamische broncode te wijzigen (bijvoorbeeld: myFunction = Function(myFunction.toString().replace(/Hello/,'Hola')); ), zal het niet werken als myFunction een closing is (natuurlijk, u je zou er niet aan denken om de bronregels tijdens runtime te vervangen, maar ...).
  • U kunt de functie-declaraties binnen de functieverklaringen binnen de mdash-functies krijgen en u kunt meer dan één niveau benaderen.
  • Ik denk dat sluiting meestal een term is voor zowel een functie als voor vastgelegde variabelen. Houd er rekening mee dat ik deze definitie in dit artikel niet gebruik!
  • Ik vermoed dat sluitingen in JavaScript anders zijn dan die in functionele talen.
  • mededeling

    dank aan

    Als je net hebt ontdekt dat je sluit (hier of ergens anders!), Dan ben ik geïnteresseerd in feedback van jou over eventuele wijzigingen die je zou kunnen voorstellen om dit artikel duidelijker te maken. Stuur een bericht naar morrisjohns.com (morris_closure @). Houd er rekening mee dat ik geen JavaScript-goeroe ben - niet aan het einde.


    De originele post van Morris is te vinden in het internetarchief .

    6329
    21 сент. het antwoord wordt gegeven door Joel Anair 21 september . 2008-09-21 17:18 '08 om 17:18 2008-09-21 17:18

    Telkens wanneer u het functiezoekwoord in een andere functie ziet, heeft de interne functie toegang tot de variabelen in de externe functie.

     function foo(x) { var tmp = 3; return function (y) { console.log(x + y + (++tmp)); // will also log 16 } } var bar = foo(2); // bar is now a closure. bar(10); 

    De bovenstaande functie zal ook 16 schrijven, omdat de bar nog steeds naar x en tmp kan verwijzen, zelfs als deze niet >

    Omdat tmp nog steeds rond de sluiting van de binnenbalk hangt, neemt het echter ook toe. Telkens wanneer u de bar belt bar .

    Het eenvoudigste voorbeeld van een sluiting is het volgende:

     function foo(x) { var tmp = 3; return function (y) { console.log(x + y + tmp); x.memb = x.memb ? x.memb + 1 : 1; console.log(x.memb); } } var age = new Number(2); var bar = foo(age); // bar is now a closure referencing age. bar(10); 

    Zoals verwacht, zal elke aanroep van bar(10) x.memb . Je kunt niet verwachten dat x simpelweg verwijst naar hetzelfde object als de age ! Na een paar telefoontjes naar bar age.memb zullen er 2 zijn! Deze link dient als basis voor geheugenlekken met HTML-objecten.

    3825
    21 сент. antwoord gegeven aan Ali op 21 sept. 2008-09-21 18:16 '08 om 18:16 2008-09-21 18:16

    VOORWOORD: dit antwoord is geschreven toen de vraag was:

    Net als de oude Albert zei hij: "Als je dit niet kunt uitleggen aan een zesjarig kind, begrijp je het zelf niet." Nou, ik probeerde de sluiting van de JS uit te leggen aan een 27-jarige vriend en faalde volledig.

    Zou iemand kunnen denken dat ik 6 ben, en vreemd genoeg geïnteresseerd in deze kwestie?

    Ik ben er vrij zeker van dat ik een van die mensen was die de eerste vraag letterlijk probeerde te nemen. Sindsdien is deze vraag meerdere malen gemuteerd, dus mijn antwoord kan nu ongelooflijk stom en ongepast lijken. Ik hoop dat het algemene idee van dit verhaal interessant blijft.


    Ik ben een grote fan van analogieën en metaforen in het uitleggen van complexe concepten, dus laat me de geschiedenis eens proberen.

    Er was eens:

    Er was een prinses ...

     function princess() { 

    Ze leefde in een wondere wereld vol avontuur. Ze ontmoette haar prins Charles, reed rond haar wereld op een eenhoorn, vocht met draken, ontmoette sprekende dieren en vele andere fantastische dingen.

      var adventures = []; function princeCharming() {  } var unicorn = {  }, dragons = [  ], squirrel = "Hello!";  

    Maar ze moest altijd terugkeren naar haar saaie wereld van problemen en volwassenen.

      return { 

    En ze vertelde hen vaak over haar laatste geweldige avontuur als een prinses.

      story: function() { return adventures[adventures.length - 1]; } }; } 

    Maar alles wat ze zagen was een klein meisje ...

     var littleGirl = princess(); 

    ... verhalen vertellen over magie en fantasie.

     littleGirl.story(); 

    En terwijl volwassenen wisten van echte prinsessen, zouden ze nooit in eenhoorns of draken geloven, omdat ze ze nooit zagen. Volwassenen zeiden dat ze alleen in de verbeelding van een klein meisje bestaan.

    Maar we kennen de ware waarheid; dat kleine meisje met een prinses erin ...

    ... eigenlijk een prinses met een klein meisje erin.

    2273
    24 июня '11 в 21:49 2011-06-24 21:49 het antwoord wordt gegeven door Jacob Swartwood op 24 juni '11 om 21:49 uur 2011-06-24 21:49

    Als we deze vraag serieus nemen, moeten we erachter komen dat een typische 6-jarige persoon cognitief in staat is, hoewel diegenen die geïnteresseerd zijn in JavaScript, niet zo typerend zijn.

    Over de ontwikkeling van de kindertijd: van 5 tot 7 jaar wordt gezegd:

    Uw kind kan instructies in twee stappen volgen. Als u bijvoorbeeld tegen uw kind zegt: "Ga naar de keuken en pak een vuilniszak", kunnen ze zich deze richting herinneren.

    We kunnen dit voorbeeld gebruiken om sluitingen als volgt uit te leggen:

    Een keuken is dichtbij en er is een lokale variabele genaamd trashBags . In de keuken is een getTrashBag functie die één vuilniszak ontvangt en teruggeeft.

    We kunnen dit als volgt in javascript coderen:

    696
    ответ дан dlaliberte 02 сент. '11 в 18:23 2011-09-02 18:23

    Соломенный человек