Wat is een ‘sluiting’?

Ik stelde een vraag over Currying en sluitingen werden genoemd.
Wat is een sluiting? Hoe verhoudt het zich tot curryen?


Antwoord 1, autoriteit 100%

Variabel bereik

Als je een lokale variabele declareert, heeft die variabele een bereik. Over het algemeen bestaan lokale variabelen alleen binnen het blok of de functie waarin je ze declareert.

function() {
  var a = 1;
  console.log(a); // works
}    
console.log(a); // fails

Als ik toegang probeer te krijgen tot een lokale variabele, zoeken de meeste talen ernaar in het huidige bereik en vervolgens omhoog door het bovenliggende bereik totdat ze het hoofdbereik bereiken.

var a = 1;
function() {
  console.log(a); // works
}    
console.log(a); // works

Als een blok of functie klaar is, zijn de lokale variabelen niet langer nodig en worden ze meestal uit het geheugen geblazen.

Dit is hoe we normaal gesproken verwachten dat dingen werken.

Een sluiting is een persistent lokaal variabel bereik

Een sluiting is een persistent bereik dat lokale variabelen vasthoudt, zelfs nadat de code-uitvoering uit dat blok is verplaatst. Talen die sluiting ondersteunen (zoals JavaScript, Swift en Ruby) stellen u in staat een verwijzing naar een bereik (inclusief de bovenliggende bereiken) te behouden, zelfs nadat het blok waarin die variabelen zijn gedeclareerd, is voltooid, op voorwaarde dat u een verwijzing behoudt naar dat blok of die functie ergens.

Het scope-object en al zijn lokale variabelen zijn gekoppeld aan de functie en blijven bestaan zolang die functie blijft bestaan.

Dit geeft ons functieportabiliteit. We kunnen verwachten dat alle variabelen die binnen het bereik waren toen de functie voor het eerst werd gedefinieerd, nog steeds binnen het bereik vallen wanneer we de functie later aanroepen, zelfs als we de functie in een geheel andere context aanroepen.

Bijvoorbeeld

Hier is een heel eenvoudig voorbeeld in JavaScript dat het punt illustreert:

outer = function() {
  var a = 1;
  var inner = function() {
    console.log(a);
  }
  return inner; // this returns a function
}
var fnc = outer(); // execute outer to get inner 
fnc();

Hier heb ik een functie binnen een functie gedefinieerd. De innerlijke functie krijgt toegang tot alle lokale variabelen van de buitenste functie, inclusief a. De variabele avalt binnen het bereik van de innerlijke functie.

Normaal gesproken worden alle lokale variabelen weggeblazen wanneer een functie wordt afgesloten. Als we echter de inner-functie retourneren en deze toewijzen aan een variabele fnczodat deze blijft bestaan nadat outeris afgesloten, alle variabelen die in het bereik waren toen innerwerd ook gedefinieerd als persistent. De variabele ais afgesloten — het valt binnen een afsluiting.

Merk op dat de variabele avolledig privé is voor fnc. Dit is een manier om privévariabelen te maken in een functionele programmeertaal zoals JavaScript.

Zoals je misschien wel kunt raden, drukt het de waarde van aaf, wat “1” is als ik aaanroep.

In een taal zonder sluiting, zou de variabele aals afval zijn verzameld en weggegooid toen de functie outerwerd afgesloten. Als u fnc aanroept, zou er een fout zijn opgetreden omdat aniet meer bestaat.

In JavaScript blijft de variabele abestaan omdat het bereik van de variabele wordt gemaakt wanneer de functie voor het eerst wordt gedeclareerd en blijft bestaan zolang de functie blijft bestaan.

abehoort tot het bereik van outer. De scope van innerheeft een bovenliggende pointer naar de scope van outer. fncis een variabele die verwijst naar inner. ablijft bestaan zolang fncblijft bestaan. avalt binnen de sluiting.


Antwoord 2, autoriteit 12%

Ik zal een voorbeeld geven (in JavaScript):

function makeCounter () {
  var count = 0;
  return function () {
    count += 1;
    return count;
  }
}
var x = makeCounter();
x(); returns 1
x(); returns 2
...etc...

Wat deze functie, makeCounter, doet, is dat het een functie retourneert, die we x hebben genoemd, die elke keer dat deze wordt aangeroepen met één wordt opgeteld. Aangezien we geen parameters aan x verstrekken, moet het op de een of andere manier de telling onthouden. Het weet waar het te vinden is op basis van wat lexicale scoping wordt genoemd – het moet naar de plek kijken waar het is gedefinieerd om de waarde te vinden. Deze “verborgen” waarde wordt een sluiting genoemd.

Hier is nogmaals mijn voorbeeld:

function add (a) {
  return function (b) {
    return a + b;
  }
}
var add3 = add(3);
add3(4); returns 7

Wat je kunt zien is dat wanneer je add aanroept met de parameter a (wat is 3), die waarde is opgenomen in de sluiting van de geretourneerde functie die we definiëren als add3. Op die manier weet het, wanneer we add3 aanroepen, waar het de a-waarde kan vinden om de optelling uit te voeren.


Antwoord 3, autoriteit 8%

Ten eerste, in tegenstelling tot wat de meeste mensen hier je vertellen, is afsluiten geeneen functie! Dus wat ishet?
Het is een setvan symbolen gedefinieerd in de “omringende context” van een functie (bekend als de omgeving) die het een GESLOTEN uitdrukking maken (dat wil zeggen, een uitdrukking waarin elk symbool is gedefinieerd en heeft een waarde, zodat het kan worden geëvalueerd).

Als u bijvoorbeeld een JavaScript-functie heeft:

function closed(x) {
  return x + 3;
}

het is een gesloten uitdrukkingomdat alle symbolen die erin voorkomen erin zijn gedefinieerd (hun betekenis is duidelijk), zodat je het kunt evalueren. Met andere woorden, het is op zichzelf staand.

Maar als je een functie als deze hebt:

function open(x) {
  return x*y + 3;
}

het is een open uitdrukkingomdat er symbolen in staan die er niet in gedefinieerd zijn. Namelijk y. Als we naar deze functie kijken, kunnen we niet zeggen wat yis en wat het betekent, we kennen de waarde niet, dus we kunnen deze uitdrukking niet evalueren. D.w.z. we kunnen deze functie pas aanroepen als we weten wat yerin moet betekenen. Deze ywordt een vrije variabelegenoemd.

Deze ysmeekt om een definitie, maar deze definitie maakt geen deel uit van de functie – hij wordt ergens anders gedefinieerd, in zijn “omringende context” (ook bekend als de omgeving). Daar hopen we tenminste op 😛

Het kan bijvoorbeeld globaal worden gedefinieerd:

var y = 7;
function open(x) {
  return x*y + 3;
}

Of het kan worden gedefinieerd in een functie die het omhult:

var global = 2;
function wrapper(y) {
  var w = "unused";
  return function(x) {
    return x*y + 3;
  }
}

Het deel van de omgeving dat de vrije variabelen in een uitdrukking hun betekenis geeft, is de sluiting. Het wordt op deze manier genoemd, omdat het een openexpressie verandert in een geslotenexpressie, door deze ontbrekende definities op te geven voor al zijn vrije variabelen, zodat we het konden evalueren.

In het bovenstaande voorbeeld is de innerlijke functie (die we geen naam hebben gegeven omdat we die niet nodig hadden) een open expressieomdat de variabele ydaarin is vrij– de definitie ervan ligt buiten de functie, in de functie die het omhult. De omgevingvoor die anonieme functie is de reeks variabelen:

{
  global: 2,
  w: "unused",
  y: [whatever has been passed to that wrapper function as its parameter `y`]
}

De afsluitingis dat deel van deze omgeving dat de innerlijke functie sluitdoor de definities te leveren voor al zijn vrije variabelen. In ons geval was de enige vrije variabele in de innerlijke functie y, dus de sluiting van die functie is deze subset van zijn omgeving:

{
  y: [whatever has been passed to that wrapper function as its parameter `y`]
}

De andere twee symbolen die in de omgeving zijn gedefinieerd, maken geendeel uit van de afsluitingvan die functie, omdat ze niet hoeven te worden uitgevoerd. Ze zijn niet nodig om het te sluiten.

Meer over de theorie hierachter:
https://stackoverflow.com/a/36878651/434562

Het is de moeite waard om op te merken dat in het bovenstaande voorbeeld de wrapper-functie zijn innerlijke functie als een waarde retourneert. Het moment dat we deze functie aanroepen kan ver in de tijd liggen vanaf het moment dat de functie is gedefinieerd (of aangemaakt). In het bijzonder is de wrap-functie niet langer actief en zijn de parameters die op de call-stack stonden er niet meer:P Dit geeft een probleem, omdat de innerlijke functie ynodig heeft om aanwezig te zijn wanneer deze wordt genoemd! Met andere woorden, het vereist dat de variabelen van de sluiting op de een of andere manier de wrapper-functie overlevenen aanwezig zijn wanneer dat nodig is. Daarom moet de innerlijke functie een snapshotmaken van deze variabelen die de sluiting maken en ze ergens veilig opslaan voor later gebruik. (Ergens buiten de call-stack.)

En dit is de reden waarom mensen de term afsluitingvaak verwarren met dat speciale type functie dat dergelijke snapshots kan maken van de externe variabelen die ze gebruiken, of de gegevensstructuur die wordt gebruikt om deze variabelen op te slaan voor later . Maar ik hoop dat je nu begrijpt dat ze nietde afsluiting zelf zijn – het zijn gewoon manieren om afsluitingen te implementerenin een programmeertaal, of taalmechanismen die de variabelen van de sluiting van de functie om er te zijn wanneer dat nodig is. Er zijn veel misvattingen over sluitingen die dit onderwerp (onnodig) veel verwarrender en ingewikkelder maken dan het in werkelijkheid is.


Antwoord 4, autoriteit 7%

Kyle’s antwoordis redelijk goed. Ik denk dat de enige aanvullende verduidelijking is dat de sluiting in feite een momentopname is van de stapel op het moment dat de lambda-functie wordt gemaakt. Wanneer de functie vervolgens opnieuw wordt uitgevoerd, wordt de stapel in die staat hersteld voordat de functie wordt uitgevoerd. Dus, zoals Kyle vermeldt, is die verborgen waarde (count) beschikbaar wanneer de lambda-functie wordt uitgevoerd.


Antwoord 5, autoriteit 4%

Een sluiting is een functie die kan verwijzen naar de status in een andere functie. In Python gebruikt dit bijvoorbeeld de sluiting “inner”:

def outer (a):
    b = "variable in outer()"
    def inner (c):
        print a, b, c
    return inner
# Now the return value from outer() can be saved for later
func = outer ("test")
func (1) # prints "test variable in outer() 1

Antwoord 6, autoriteit 3%

Om het begrip van afsluitingen te vergemakkelijken, kan het nuttig zijn om te onderzoeken hoe ze in een procedurele taal kunnen worden geïmplementeerd. Deze uitleg volgt een simplistische implementatie van sluitingen in Schema.

Om te beginnen moet ik het concept van een naamruimte introduceren. Wanneer u een opdracht invoert in een Schema-interpreter, moet deze de verschillende symbolen in de uitdrukking evalueren en hun waarde verkrijgen. Voorbeeld:

(define x 3)
(define y 4)
(+ x y) returns 7

De gedefinieerde expressies slaan de waarde 3 in de spot op voor x en de waarde 4 op de plek voor y. Wanneer we vervolgens (+ x y) aanroepen, zoekt de interpreter de waarden op in de naamruimte en kan de bewerking uitvoeren en 7 retourneren.

In Schema zijn er echter uitdrukkingen waarmee u de waarde van een symbool tijdelijk kunt overschrijven. Hier is een voorbeeld:

(define x 3)
(define y 4)
(let ((x 5))
   (+ x y)) returns 9
x returns 3

Wat het let-sleutelwoord doet, is een nieuwe naamruimte introduceren met x als de waarde 5. U zult merken dat het nog steeds kan zien dat y 4 is, waardoor de som terugkomt op 9. U kunt dat ook zien zodra de uitdrukking is afgelopen x is weer 3. In die zin is x tijdelijk gemaskeerd door de lokale waarde.

Procedurele en objectgeoriënteerde talen hebben een soortgelijk concept. Telkens wanneer u een variabele declareert in een functie die dezelfde naam heeft als een globale variabele, krijgt u hetzelfde effect.

Hoe zouden we dit implementeren? Een eenvoudige manier is met een gekoppelde lijst – de kop bevat de nieuwe waarde en de staart bevat de oude naamruimte. Als je een symbool moet opzoeken, begin je bij de kop en werk je naar beneden langs de staart.

Laten we nu naar de implementatie van eersteklas functies gaan. Een functie is min of meer een reeks instructies die moet worden uitgevoerd wanneer de functie wordt aangeroepen, met als hoogtepunt de geretourneerde waarde. Wanneer we een functie inlezen, kunnen we deze instructies achter de schermen opslaan en uitvoeren wanneer de functie wordt aangeroepen.

(define x 3)
(define (plus-x y)
  (+ x y))
(let ((x 5))
  (plus-x 4)) returns ?

We definiëren x als 3 en plus-x als zijn parameter, y, plus de waarde van x. Ten slotte noemen we plus-x in een omgeving waar x is gemaskeerd door een nieuwe x, deze waarde 5 heeft. Als we alleen de bewerking (+ xy) opslaan voor de functie plus-x, aangezien we in de context als x 5 is, zou het geretourneerde resultaat 9 zijn. Dit wordt dynamische scoping genoemd.

Schema, Common Lisp en vele andere talen hebben echter wat lexicale scoping wordt genoemd – naast het opslaan van de bewerking (+ x y) slaan we ook de naamruimte op dat specifieke punt op. Op die manier kunnen we, wanneer we de waarden opzoeken, zien dat x, in deze context, echt 3 is. Dit is een afsluiting.

(define x 3)
(define (plus-x y)
  (+ x y))
(let ((x 5))
  (plus-x 4)) returns 7

Samengevat kunnen we een gekoppelde lijst gebruiken om de status van de naamruimte op het moment van de functiedefinitie op te slaan, waardoor we toegang hebben tot variabelen van omsluitende scopes, en ons ook de mogelijkheid bieden om een variabele lokaal te maskeren zonder de rest van het programma.


Antwoord 7

Functies die geen vrije variabelen bevatten, worden pure functies genoemd.

Functies die een of meer vrije variabelen bevatten, worden afsluitingen genoemd.

var pure = function pure(x){
  return x 
  // only own environment is used
}
var foo = "bar"
var closure = function closure(){
  return foo 
  // foo is a free variable from the outer environment
}

src: https://leanpub.com/javascriptallongesix/read#leanpub-auto-if-functions-without-free-variables-are-pure-are-closures-onzuiver


Antwoord 8

Hier is een voorbeeld uit de praktijk van waarom Closures een kick ass is… Dit komt rechtstreeks uit mijn Javascript-code. Laat me illustreren.

Function.prototype.delay = function(ms /*[, arg...]*/) {
  var fn = this,
      args = Array.prototype.slice.call(arguments, 1);
  return window.setTimeout(function() {
      return fn.apply(fn, args);
  }, ms);
};

En zo zou je het gebruiken:

var startPlayback = function(track) {
  Player.play(track);  
};
startPlayback(someTrack);

Stel je nu voor dat je wilt dat het afspelen wordt gestart, zoals bijvoorbeeld 5 seconden later nadat deze code fragmenteert. Nou dat is gemakkelijk met delayen het is sluiting:

startPlayback.delay(5000, someTrack);
// Keep going, do other things

Wanneer u delaymet 5000MS, loopt het eerste fragment en slaat de eerste argumenten in zijn sluiting op. Vervolgens 5 seconden later, wanneer de setTimeoutcallback gebeurt, handhaaft de sluiting nog steeds die variabelen, zodat het de originele functie kan bellen met de originele parameters.
Dit is een type currying of functie-decoratie.

Zonder sluitingen zou u op de een of andere manier die variabelen buiten de functie moeten handhaven, waardoor de code buiten de functie wordt afgetrokken met iets dat logisch in de binnenkant behoort. Het gebruik van sluitingen kan de kwaliteit en leesbaarheid van uw code aanzienlijk verbeteren.


Antwoord 9

TL; DR

Een sluiting is een functie en de reikwijdte die is toegewezen aan (of gebruikt als) een variabele. Dus de naam sluiting: de reikwijdte en de functie zijn ingesloten en gebruikt net als elke andere entiteit.

in de diepte Wikipedia-stijl Uitleg

Volgens Wikipedia is een sluiting :

Technieken voor het implementeren van lexicaal scoped naambinding in talen met eersteklas functies.

Wat betekent dat? Laten we in sommige definities kijken.

Ik zal afsluitingen en andere gerelateerde definities uitleggen door dit voorbeeld te gebruiken:

function startAt(x) {
    return function (y) {
        return x + y;
    }
}
var closure1 = startAt(1);
var closure2 = startAt(5);
console.log(closure1(3)); // 4 (x == 1, y == 3)
console.log(closure2(3)); // 8 (x == 5, y == 3)

Antwoord 10

Sluitingis een functie in JavaScript waarbij een functie toegang heeft tot zijn eigen bereikvariabelen, toegang tot de buitenste functievariabelen en toegang tot de globale variabelen.

Sluiting heeft toegang tot het bereik van de buitenste functie, zelfs nadat de buitenste functie is teruggekeerd. Dit betekent dat een sluiting variabelen en argumenten van zijn buitenste functie kan onthouden en benaderen, zelfs nadat de functie is afgelopen.

De binnenste functie heeft toegang tot de variabelen die zijn gedefinieerd in zijn eigen bereik, het bereik van de buitenste functie en het globale bereik. En de buitenste functie heeft toegang tot de variabele die is gedefinieerd in zijn eigen bereik en het globale bereik.

Voorbeeld van sluiting:

var globalValue = 5;
function functOuter() {
  var outerFunctionValue = 10;
  //Inner function has access to the outer function value
  //and the global variables
  function functInner() {
    var innerFunctionValue = 5;
    alert(globalValue + outerFunctionValue + innerFunctionValue);
  }
  functInner();
}
functOuter();  

Uitvoer zal 20 zijn, welke som van de interne functievariabele, buitenste functievariabele en globale variabele waarde.


Antwoord 11

In een normale situatie zijn variabelen gebonden aan een bereikregel: lokale variabelen werken alleen binnen de gedefinieerde functie. Afsluiten is een manier om deze regel tijdelijk te overtreden voor het gemak.

def n_times(a_thing)
  return lambda{|n| a_thing * n}
end

in de bovenstaande code is lambda(|n| a_thing * n}de afsluiting omdat naar a_thingwordt verwezen door de lambda (een anonieme maker van een functie).

p>

Als je nu de resulterende anonieme functie in een functievariabele plaatst.

foo = n_times(4)

foo zal de normale scopingregel overtreden en 4 intern gaan gebruiken.

foo.call(3)

retourneert 12.


Antwoord 12

Kortom, functieaanwijzer is slechts een aanwijzer naar een locatie in de programmacodebasis (zoals een programmateller). Overwegende dat Sluiting = Functieaanwijzer + Stapelframe.

.


Antwoord 13

• Een afsluiting is een subprogramma en de
verwijzen naar de omgeving waar het was
gedefinieerd

– De referentieomgeving is nodig als het subprogramma
kan vanaf elke willekeurige plaats in het programma worden aangeroepen

– Een taal met een statisch bereik die genest niet toestaat
subprogramma’s hebben geen sluitingen nodig

– Sluitingen zijn alleen nodig als een subprogramma toegang heeft
variabelen in nesting scopes en kan worden aangeroepen vanuit
overal

– Om sluitingen te ondersteunen, moet een implementatie mogelijk:
bieden onbeperkte mate aan sommige variabelen (omdat a
subprogramma kan toegang krijgen tot een niet-lokale variabele die:
normaal gesproken niet meer in leven)

Voorbeeld

function makeAdder(x) {
return function(y) {return x + y;}
}
var add10 = makeAdder(10);
var add5 = makeAdder(5);
document.write(″add 10 to 20: ″ + add10(20) +
″<br />″);
document.write(″add 5 to 20: ″ + add5(20) +
″<br />″);

Antwoord 14

Een sluiting is een stateful functie die wordt geretourneerd door een andere functie. Het fungeert als een container om variabelen en parameters uit het bovenliggende bereik te onthouden, zelfs als de bovenliggende functie is uitgevoerd. Overweeg dit eenvoudige voorbeeld.

 function sayHello() {
  const greeting = "Hello World";
  return function() { // anonymous function/nameless function
    console.log(greeting)
  }
}
const hello = sayHello(); // hello holds the returned function
hello(); // -> Hello World

Kijk! we hebben een functie die een functie retourneert! De geretourneerde functie wordt opgeslagen in een variabele en roept de onderstaande regel op.


Antwoord 15

Hier is nog een voorbeeld uit de praktijk, en met een scripttaal die populair is in games: Lua. Ik moest de manier waarop een bibliotheekfunctie werkte enigszins veranderen om te voorkomen dat stdin niet beschikbaar was.

local old_dofile = dofile
function dofile( filename )
  if filename == nil then
    error( 'Can not use default of stdin.' )
  end
  old_dofile( filename )
end

De waarde van old_dofile verdwijnt wanneer dit codeblok zijn bereik voltooit (omdat het lokaal is), maar de waarde is ingesloten in een sluiting, dus de nieuwe opnieuw gedefinieerde dofile-functie KAN er toegang toe krijgen, of liever een kopie opgeslagen samen met de functioneren als een ‘upvalue’.


Antwoord 16

Van Lua.org:

Als een functie in een andere functie wordt geschreven, heeft deze volledige toegang tot lokale variabelen vanuit de omsluitende functie; deze functie wordt lexicale scoping genoemd. Hoewel dat misschien vanzelfsprekend klinkt, is het dat niet. Lexicale scoping, plus eersteklas functies, is een krachtig concept in een programmeertaal, maar weinig talen ondersteunen dat concept.


Antwoord 17

Als je uit de Java-wereld komt, kun je een afsluiting vergelijken met een lidfunctie van een klasse. Kijk naar dit voorbeeld

var f=function(){
  var a=7;
  var g=function(){
    return a;
  }
  return g;
}

De functie gis een afsluiting: gsluit ain. Dus gkan worden vergeleken met een lidfunctie, akan worden vergeleken met een klasseveld, en de functie fmet een klasse.


Antwoord 18

Sluitingen
Telkens wanneer we een functie hebben gedefinieerd in een andere functie, heeft de innerlijke functie toegang tot de gedeclareerde variabelen
in de uiterlijke functie. Sluitingen kunnen het beste worden uitgelegd met voorbeelden.
In Listing 2-18 kunt u zien dat de inner-functie toegang heeft tot een variabele (variableInOuterFunction) van de
buitenste bereik. De variabelen in de buitenste functie zijn gesloten door (of gebonden in) de binnenste functie. vandaar de term
sluiting. Het concept op zich is eenvoudig genoeg en redelijk intuïtief.

Listing 2-18:
    function outerFunction(arg) {
     var variableInOuterFunction = arg;
     function bar() {
             console.log(variableInOuterFunction); // Access a variable from the outer scope
     }
     // Call the local function to demonstrate that it has access to arg
     bar(); 
    }
    outerFunction('hello closure!'); // logs hello closure!

bron: http://index-of.es/Varios/Basarat%20Ali%20Syed%20(auth.)-Beginning%20Node.js-Apress%20(2014).pdf


Antwoord 19

Kijk eens naar onderstaande code om de sluiting beter te begrijpen:

       for(var i=0; i< 5; i++){            
            setTimeout(function(){
                console.log(i);
            }, 1000);                        
        }

Wat wordt hier uitgevoerd? 0,1,2,3,4niet dat wordt 5,5,5,5,5wegens sluiting

Dus hoe het zal oplossen? Het antwoord staat hieronder:

      for(var i=0; i< 5; i++){
           (function(j){     //using IIFE           
                setTimeout(function(){
                               console.log(j);
                           },1000);
            })(i);          
        }

Laat me het simpel uitleggen, wanneer een functie gemaakt is, gebeurt er niets totdat het de for-lus in de 1e code 5 keer aanroept, maar niet onmiddellijk aanroept, dus toen het aanriep, dwz na 1 seconde en ook dit is asynchroon dus voordat deze for-lus eindigde en sla waarde 5 op in var i en voer ten slotte de functie setTimeoutvijf keer uit en druk 5,5,5,5,5

af

Hier hoe het oplost met IIFE, d.w.z. Immediate Invoking Function Expression

      (function(j){  //i is passed here           
            setTimeout(function(){
                           console.log(j);
                       },1000);
        })(i);  //look here it called immediate that is store i=0 for 1st loop, i=1 for 2nd loop, and so on and print 0,1,2,3,4

Begrijp voor meer informatie de uitvoeringscontext om de afsluiting te begrijpen.

  • Er is nog een oplossing om dit op te lossen met let (ES6-functie) maar onder de motorkap hierboven werkt de functie

    for(let i=0; i< 5; i++){           
         setTimeout(function(){
                        console.log(i);
                    },1000);                        
     }
    Output: 0,1,2,3,4
    

=> Meer uitleg:

In het geheugen, als de for-loop afbeelding wordt uitgevoerd, zoals hieronder:

Loop 1)

    setTimeout(function(){
                    console.log(i);
                },1000);  

Loop 2)

    setTimeout(function(){
                    console.log(i);
                },1000);  

Loop 3)

    setTimeout(function(){
                    console.log(i);
                },1000);  

Loop 4)

    setTimeout(function(){
                    console.log(i);
                },1000);  

Loop 5)

    setTimeout(function(){
                    console.log(i);
                },1000);  

Hier wordt i niet uitgevoerd en dan, na de volledige lus, slaat var i waarde 5 op in het geheugen, maar het bereik is altijd zichtbaar in de onderliggende functie, dus wanneer de functie vijf keer wordt uitgevoerd binnen setTimeout, wordt 5,5,5,5,5

dus om dit op te lossen, gebruik IIFE zoals hierboven uitgelegd.


Antwoord 20

Currying: Hiermee kunt u een functie gedeeltelijk evalueren door alleen een subset van zijn argumenten door te geven. Overweeg dit:

function multiply (x, y) {
  return x * y;
}
const double = multiply.bind(null, 2);
const eight = double(4);
eight == 8;

Sluiting: een sluiting is niets meer dan toegang tot een variabele buiten het bereik van een functie. Het is belangrijk om te onthouden dat een functie binnen een functie of een geneste functie geen sluiting is. Sluitingen worden altijd gebruikt wanneer toegang tot de variabelen buiten het functiebereik nodig is.

function apple(x){
   function google(y,z) {
    console.log(x*y);
   }
   google(7,2);
}
apple(3);
// the answer here will be 21

Antwoord 21

Sluiten is heel eenvoudig. We kunnen het als volgt beschouwen:
Sluiting = functie + zijn lexicale omgeving

Overweeg de volgende functie:

function init() {
    var name = “Mozilla”;
}

Wat zal de sluiting zijn in het bovenstaande geval?
Functie init() en variabelen in zijn lexicale omgeving, dwz naam.
Sluiting= init() + naam

Overweeg een andere functie:

function init() {
    var name = “Mozilla”;
    function displayName(){
        alert(name);
}
displayName();
}

Wat zullen hier de sluitingen zijn?
Binnenfunctie heeft toegang tot variabelen van de buitenfunctie. displayName() heeft toegang tot de variabelenaam die is gedeclareerd in de bovenliggende functie, init(). Dezelfde lokale variabelen in displayName() zullen echter worden gebruikt als ze bestaan.

Sluiting 1:init functie + ( naam variabele + displayName() functie) –> lexicale reikwijdte

Sluiting 2 :displayName functie + ( naam variabele ) –> lexicale reikwijdte


Antwoord 22

Sluitingen voorzien JavaScript van status.

Status in programmeren betekent simpelweg dingen onthouden.

Voorbeeld

var a = 0;
a = a + 1; // => 1
a = a + 1; // => 2
a = a + 1; // => 3

In het bovenstaande geval wordt de status opgeslagen in de variabele “a”. We volgen door meerdere keren 1 toe te voegen aan “a”. Dat kunnen we alleen doen omdat we de waarde kunnen ‘onthouden’. De statushouder, “a”, houdt die waarde in het geheugen.

Vaak wil je in programmeertalen dingen bijhouden, informatie onthouden en deze op een later tijdstip openen.

Dit, in andere talen, wordt gewoonlijk bereikt door het gebruik van klassen. Een klasse houdt, net als variabelen, zijn status bij. En gevallen van die klasse hebben op hun beurt ook een staat in zich. Status betekent eenvoudigweg informatie die u kunt opslaan en later kunt ophalen.

Voorbeeld

class Bread {
  constructor (weight) {
    this.weight = weight;
  }
  render () {
    return `My weight is ${this.weight}!`;
  }
}

Hoe kunnen we toegang krijgen tot “gewicht” vanuit de “render”-methode? Nou, dankzij de staat. Elke instantie van de klasse Bread kan zijn eigen gewicht weergeven door het te lezen vanuit de “state”, een plaats in het geheugen waar we die informatie zouden kunnen opslaan.

Nu is JavaScript een zeer unieke taaldie historisch gezien geen klassen heeft (nu wel, maar onder de motorkap zijn er alleen functies en variabelen), dus sluitingen bieden JavaScript een manier om dingen te onthouden en bekijk ze later.

Voorbeeld

var n = 0;
var count = function () {
  n = n + 1;
  return n;
};
count(); // # 1
count(); // # 2
count(); // # 3

Met het bovenstaande voorbeeld is het doel van ‘status behouden’ met een variabele bereikt. Dit is geweldig! Dit heeft echter het nadeel dat de variabele (de “state” houder) nu bloot komt te liggen. Wij kunnen het beter. We kunnen sluitingen gebruiken.

Voorbeeld

var countGenerator = function () {
  var n = 0;
  var count = function () {
    n = n + 1;
    return n;
  };
  return count;
};
var count = countGenerator();
count(); // # 1
count(); // # 2
count(); // # 3

Dit is fantastisch.

Nu kan onze “tel”-functie tellen. Het is alleen in staat om dit te doen omdat het de staat kan “houden”. De toestand is in dit geval de variabele “n”. Deze variabele is nu gesloten. Gesloten in tijd en ruimte. Op tijd omdat je het nooit kunt herstellen, wijzigen, een waarde toewijzen of er rechtstreeks mee communiceren. In de ruimte omdat het geografisch genest is binnen de functie “countGenerator”.

Waarom is dit fantastisch? Omdat we zonder een ander geavanceerd en gecompliceerd hulpmiddel (bijv. klassen, methoden, instanties, enz.)
1. verbergen
2. controle op afstand

We verbergen de status, de variabele “n”, waardoor het een privévariabele wordt!
We hebben ook een API gemaakt die deze variabele op een vooraf gedefinieerde manier kan regelen. We kunnen in het bijzonder de API zoals SO “noemen, dus” Count () “en dat voegt 1 toe aan” N “van een” afstand “. Op geen enkele manier zal vorm of vorm iemand ooit toegang hebben tot “n”, behalve via de API.

Javascript is echt verbazingwekkend in zijn eenvoud.

Sluitingen zijn een groot deel van waarom dit is.


Antwoord 23

Een eenvoudig voorbeeld in Groovy voor uw referentie:

def outer() {
    def x = 1
    return { -> println(x)} // inner
}
def innerObj = outer()
innerObj() // prints 1

Antwoord 24

Hier is een voorbeeld dat een sluiting in de programmeertaal van de regeling illustreert.

Eerst definiëren we een functie die een lokale variabele definieert, niet zichtbaar buiten de functie.

; Function using a local variable
(define (function)
  (define a 1)
  (display a) ; prints 1, when calling (function)
  )
(function) ; prints 1
(display a) ; fails: a undefined

Hier is hetzelfde voorbeeld, maar nu gebruikt de functie een globale variabele, gedefinieerd buiten de functie.

; Function using a global variable
(define b 2)
(define (function)
  (display b) ; prints 2, when calling (function)
  )
(function) ; prints 2
(display 2) ; prints 2

En ten slotte is hier een voorbeeld van een functie die zijn eigen sluiting draagt:

; Function with closure
(define (outer)
  (define c 3)
  (define (inner)
    (display c))
  inner ; outer function returns the inner function as result
  )
(define function (outer))
(function) ; prints 3

Other episodes