2016-04-25 7 views
1

Ich habe den folgenden Code zu verstehen versucht:Was die Lebensdauer von Variablen innerhalb einer Selbstaufruffunktion ist in Javascript

var add = (function() { 
     var counter = 0; 
     return function() {return counter += 1;} 
    })(); 
    add(); 
    add(); 
    add(); 

Hier add den Rückgabewert der anonymen Selbstaufruffunktion zugeordnet ist -, dass ist die Funktion function() { return counter += 1 }. Jetzt das erste Mal add() aufgerufen wird, gibt es 1 wie erwartet zurück. Aber das zweite Mal add() aufgerufen wird, gibt es 2 zurück.

Meine Frage ist seit counter ist in einer Funktion definiert, so würde nicht jedes Mal die Funktion beendet Ausführung counter sollte sterben? Das heißt, nach dem ersten Anruf wird add() 1 angezeigt. Jetzt sind wir aus dieser Funktion, sollte nicht counter vergessen, es ist der vorherige Wert und aus dem Stapel wie automatic Variablen zerstört werden?

+1

http://stackoverflow.com/questions/111102/how-do-javascript-closures-work – mplungjan

+0

Willkommen in der Welt der Schließungen. Ich schlage vor, dass Sie mit diesem Konzept herumspielen, indem Sie reguläre Funktionen anstelle von Selbstaufruffunktionen (IIFE) verwenden, um es klar von dem Konzept der anonymen Funktionen zu trennen (Anfang der 90er bis Anfang der 2000er Jahre haben viele Leute in der Community die beiden durcheinander gebracht) bis zu dem Punkt, dass einige denken, Schließungen können nur in anonymen Funktionen existieren. Es hilft nicht, dass anonyme Funktionen in einigen anderen Sprachen closures genannt werden) – slebetman

+0

Das [auto] -Tag ist spezifisch für C++ 11 und gilt sie nicht und war es entfernt. Bitte beachten Sie, wie Sie Ihre Fragen in der Zukunft markieren. –

Antwort

7

Was ist die Lebensdauer von Variablen innerhalb einer selbstaufrufende Funktion in Javascript

Die gleichen wie Variablen in jeder anderen Art von JavaScript-Funktion: Sie existieren, solange sie Bezug genommen werden kann, die manchmal bedeutet lange nach der Zeit, die die Funktion, die sie enthält, zurückgibt.

Ihre counter Variable setzt sich nach den IIFE kehrt existieren, weil die Funktion schafft es und kehrt (return function() {return counter += 1;}) ist ein Verschluss über die Variable. Die Variable existiert so lange, wie diese Funktion existiert.

Technisch: erzeugt eine Funktion aufrufen etwas ein Ausführungskontext für diesen Anruf genannt, die eine variable Umgebung Objekt hat. Jede Funktion, die während des Aufrufs erstellt wird, erhält einen Verweis auf dieses äußere variable Umgebungsobjekt; Dieses Objekt existiert, wie alle Objekte, solange es einen Bezug darauf gibt, und so halten die Funktionen das Objekt am Leben. Variablen sind tatsächlich Eigenschaften dieses Variablenumgebungsobjekts, und daher existieren sie so lange, wie etwas auf das Objekt verweist, auf dem sie sich befinden. (Dies ist die sehr vereinfachte Form.) Während in der Theorie das gesamte variable Umgebungsobjekt beibehalten wird, sind JavaScript-Engines in der Praxis frei, um zu optimieren, wenn die Effekte der Optimierung nicht beobachtbar sind, also eine Variable, die nicht tatsächlich vom Abschluss verwendet wird kann (oder möglicherweise nicht) freigegeben werden, abhängig vom Motor und dem Code in der Funktion.

Ihr IIFE kann nur einmal aufgerufen werden. Es kann also nur einen geben counter, aber es ist üblich, dass eine Funktion zum Erstellen einer Closure mehrmals aufgerufen wird. In diesem Fall haben Sie mehrere variable Objekte und mehrere Kopien Variablen, die geschlossen sind.

Beispiel:

function helloBuilder(name) { 
 
    var counter = 0; 
 
    return function() { 
 
    ++counter; 
 
    display("Hi there, " + name + ", this is greeting #" + counter); 
 
    }; 
 
} 
 

 
var helloFred = helloBuilder("Fred"); 
 
var helloMaria = helloBuilder("Maria"); 
 

 

 
helloFred(); // "Hi there, Fred, this is greeting #1" 
 
helloFred(); // "Hi there, Fred, this is greeting #2" 
 
helloMaria(); // "Hi there, Maria, this is greeting #1" 
 
helloMaria(); // "Hi there, Maria, this is greeting #2" 
 
helloFred(); // "Hi there, Fred, this is greeting #3" 
 

 
function display(msg) { 
 
    var p = document.createElement('p'); 
 
    p.appendChild(document.createTextNode(msg)); 
 
    document.body.appendChild(p); 
 
}

In der oben kehrte die Funktion durch helloBuilderschließt über sowohl seine name Argument und seine counter Variable. (Weil Argumente auch im Variablenobjekt des Ausführungskontexts gespeichert werden.) So können wir sehen, dass, nachdem es zweimal aufgerufen wurde, es zwei variable Objekte gibt, jedes mit seinen eigenen name und counter, eine referenzierte von jeder Funktion, die wir helloBuilder zu erstellen suchten.

+0

Wenn ich dich richtig verstehe, bedeutet das, dass wir einer globalen Variable 'add' eine Funktion zuweisen. Alles innerhalb der Funktion wird auf dem Stack gespeichert, einschließlich der Zählervariable. Der Zähler verhält sich also wie eine Art statische Variable. – user31782

+1

@ user31782: Nicht ganz. Es ist vielmehr so, dass der Stapel selbst eher als eine verkettete Liste als als ein Array ausgelegt ist, so dass der Stapelrahmen beim Erstellen von Verschlüssen gelöst und wieder angebracht werden kann. Finden Sie diese Antwort für die konzeptionellen Low-Level-Details, wie Schließungen mit Stapeln verbunden sind: http://StackOverflow.com/Questions/26061856/Javascript-Cant-Access-Private-Properties/26063201#26063201 – slebetman

+1

@ user31782: Nun, ' add 'muss nicht global sein, und der Inhalt des Variablenobjekts wird nicht auf dem Stapel gespeichert. Abgesehen davon, ja. Da wir einen Verweis auf die Funktion behalten, die das IIFE zurückgibt, wird das Variablenobjekt für den IIFE-Aufruf beibehalten, solange wir diese Funktion beibehalten. Und es ist ein * Bit * wie statische Variablen in C, außer dass es einen * für jeden Aufruf der Funktion * gibt. Ihr IIFE kann nur einmal aufgerufen werden, aber das ist spezifisch für Ihr Beispiel. Funktionen, die Funktionen zurückgeben, die mehr als einmal aufgerufen werden können, sind üblich. –