JavaScript-Schließungen im Vergleich zu anonymen Funktionen
Einem Freund von mir und ich sind derzeit in der Diskussion, was eine Schließung in JS ist, und was nicht. Wir wollen einfach nur sicherstellen, dass wir wirklich es richtig zu verstehen.
Nehmen wir mal dieses Beispiel. Wir haben eine zählschleife und drucken möchten, die Zähler-variable auf der Konsole verzögert. Deshalb verwenden wir setTimeout
und Verschlüsse zu erfassen den Wert der counter-variable, um sicherzustellen, dass es nicht zu drucken, die N-fache Wert N.
Die falsche Lösung, ohne Verschlüsse oder irgendetwas in der Nähe Verschlüsse wäre:
for(var i = 0; i < 10; i++) {
setTimeout(function() {
console.log(i);
}, 1000);
}
welche natürlich drucken 10-fachen Wert der i
nach der Schleife, nämlich 10.
So sein Versuch war:
for(var i = 0; i < 10; i++) {
(function(){
var i2 = i;
setTimeout(function(){
console.log(i2);
}, 1000)
})();
}
Druck 0 bis 9, wie erwartet.
Ich sagte ihm, dass er nicht mit einem Schließung zu erfassen i
aber er besteht darauf, dass er es ist. Ich habe gezeigt, dass er nicht die Verschlüsseindem Sie die for-Schleife innerhalb einer anderen setTimeout
(vorbei seinem anonymen Funktion setTimeout
), Druck 10 mal 10 wieder. Das gleiche gilt, wenn ich seine speichern-Funktion in einem var
und führen Sie es nach die Schleife, auch Druck 10 mal 10. Also mein argument ist, dass er nicht wirklich erfassen der Wert i
seine version nicht eine Schließung.
Mein Versuch war:
for(var i = 0; i < 10; i++) {
setTimeout((function(i2){
return function() {
console.log(i2);
}
})(i), 1000);
}
Also ich capture i
(benannt i2
innerhalb der closure), aber jetzt habe ich zurück eine andere Funktion auf und übergeben Sie diese um. In meinem Fall, die Funktion übergeben setTimeout wirklich erfasst i
.
Jetzt, Verschlüsse und wer nicht?
Beachten Sie, dass beide Lösungen drucken 0 bis 9 auf der Konsole verzögert, so dass Sie lösen das ursprüngliche problem, aber wir wollen verstehen, welche dieser beiden Lösungen verwendet Verschlüsse um dies zu erreichen.
InformationsquelleAutor der Frage leemes | 2012-10-17
Du musst angemeldet sein, um einen Kommentar abzugeben.
Entsprechend der
closure
definition:Sind Sie mit
closure
wenn Sie eine Funktion definieren, die eine variable definiert außerhalb der Funktion. (wir nennen Sie die variable ein freie variable).Sie alle nutzen
closure
(auch im 1. Beispiel).InformationsquelleAutor der Antwort kev
In einer nussschale Javascript Closures ermöglichen, eine Funktion zu Zugriff auf eine variableerklärt in einem lexikalisch-der übergeordneten Funktion.
Let ' s finden Sie eine ausführlichere Erklärung.
Um zu verstehen, Verschlüsse ist es wichtig zu verstehen, wie JavaScript-Bereiche von Variablen.
Bereiche
In JavaScript-Bereiche definiert und mit Funktionen.
Jede Funktion definiert einen neuen Bereich.
Betrachten Sie das folgende Beispiel;
Aufruf f druckt
Lassen Sie uns nun betrachten wir den Fall, wir haben eine Funktion
g
definiert, die innerhalb einer anderen Funktionf
.Nennen wir
f
die lexikalische Eltern vong
.Wie bereits erläutert, haben wir nun 2 Bereiche; der Bereich
f
und den Umfangg
.Aber ein Bereich ist "innerhalb" der andere Bereich, so ist der Umfang der untergeordneten Funktion Teil des Umfangs der übergeordneten Funktion? Was passiert mit den Variablen, die im Rahmen der übergeordneten Funktion; werde ich in der Lage sein Zugriff auf diese aus dem Anwendungsbereich des Kindes-Funktion?
Das ist genau das, wo Verschlüsse Schritt.
Verschlüsse
In JavaScript die Funktion
g
können nicht nur Zugriff auf alle Variablen, die im Rahmeng
aber auch Zugriff auf alle Variablen, die im Rahmen der übergeordneten Funktionf
.Erwägen;
Aufruf f druckt
Schauen wir uns die Zeile
console.log(foo);
. An diesem Punkt sind wir im Rahmeng
und wir versuchen, den Zugriff auf die variablefoo
erklärt wird im Rahmenf
. Aber wie gesagt, bevor wir Zugriff auf jede variable, die deklariert, in einem lexikalischen übergeordnete Funktion, das ist hier der Fall;g
ist die lexikalische übergeordnetef
. Daherhello
gedruckt wird.Lassen Sie uns nun einen Blick auf die Linie
console.log(bar);
. An diesem Punkt sind wir im Rahmenf
und wir versuchen, den Zugriff auf die variablebar
erklärt wird im Rahmeng
.bar
ist nicht deklariert in den aktuellen Bereich und die Funktiong
ist nicht die Muttergesellschaft vonf
daherbar
undefinedEigentlich können wir auch den Zugriff auf die Variablen, die in den Geltungsbereich eines lexikalischen "grand parent" - Funktion. Daher gäbe es eine Funktion
h
definiert, innerhalb dessen die Funktiong
dann
h
wäre in der Lage, Zugriff auf alle Variablen im Gültigkeitsbereich der Funktionh
g
undf
. Dies geschieht mit Verschlüsse. In JavaScript Verschlüsse ermöglicht uns den Zugriff auf alle Variablen deklariert, die in der lexikalischen übergeordnete Funktion, die in der lexikalischen grand übergeordnete Funktion, die in der lexikalischen grand-grand-parent-Funktion, etc.Dies kann gesehen werden als eine scope-chain;
scope of current function -> scope of lexical parent function -> scope of lexical grand parent function -> ...
bis zur letzten übergeordneten Funktion, keine lexikalische Eltern.Das window-Objekt
Eigentlich die Kette hört nicht auf das Letzte übergeordnete Funktion. Es gibt noch eine Besondere Bedeutung; die globalen Bereich. Alle Variablen sind nicht deklariert in einer Funktion berücksichtigt werden, die im globalen Gültigkeitsbereich deklariert. Die Globale Reichweite hat zwei Spezialitäten;
window
Objekt.Daher gibt es genau zwei Möglichkeiten, eine variable deklarieren
foo
im globalen Bereich; entweder, indem Sie nicht deklarieren, es in eine Funktion oder durch das setzen der Eigenschaftfoo
des window-Objekts.Beide versuche verwendet Verschlüsse
Nun, da Sie haben Lesen Sie eine genauere Erklärung, vielleicht ist es nun ersichtlich, dass beide Lösungen verwendet Verschlüsse.
Aber um sicher zu sein, lassen Sie uns einen Beweis.
Erstellen wir eine neue Programmiersprache; JavaScript-Keine-Verschluss.
Wie der name schon andeutet, JavaScript-Keine-Verschluss ist identisch mit JavaScript, außer dass es keine Unterstützung Verschlüsse.
In anderen Worten;
Okay, mal sehen, was passiert mit der ersten Lösung mit JavaScript-Keine-Verschluss;
da das drucken
undefined
10 mal in der JavaScript-Keine-Verschluss.Daher die erste Lösung verwendet Schließung.
Schauen wir uns die zweite Lösung;
da das drucken
undefined
10 mal in der JavaScript-Keine-Verschluss.Beide Lösungen verwendet Verschlüsse.
Edit: Es wird davon ausgegangen, dass die 3 code-snippets sind nicht definiert in den globalen Gültigkeitsbereich. Ansonsten werden die Variablen
foo
undi
wäre die Bindung zu derwindow
Objekt und damit zugänglich durch diewindow
Objekt sowohl in JavaScript und JavaScript-Keine-Verschluss.InformationsquelleAutor der Antwort
Ich war nie glücklich mit der Art, wie jemand dies erklärt.
Den Schlüssel zum Verständnis von closures zu verstehen, was JS wäre wie ohne Verschlüsse.
Ohne Verschlüsse, dies würde einen Fehler auslösen
Einmal outerFunc zurückgegeben hat, die in einer imaginären Schließung-deaktiviert-version von JavaScript, die Referenz zu outerVar wäre Müll gesammelt und gegangen, indem Sie gar nichts für die innere func Referenz.
Verschlüsse sind im wesentlichen die speziellen Regeln, die kick und machen es möglich, für diese vars zu existieren, wenn eine innere Funktion verweist auf einen äußeren Funktion die Variablen. Mit Verschlüssen die vars verwiesen wird, bleibt auch nach der äußeren Funktion ist getan oder 'geschlossen', wenn, die Ihnen hilft, den Punkt.
Sogar mit Verschlüssen, die den Lebenszyklus der lokalen Variable in einer Funktion ohne innere funcs, die den Verweis auf den einheimischen Werken gleichen, wie es wäre, in einer Verschluss-weniger-version. Wenn die Funktion fertig ist, den einheimischen zu bekommen, Müll gesammelt.
Sobald Sie einen Verweis auf eine innere func zu einer äußeren var, aber es ist wie ein Türrahmen gelegt bekommt in der Art von garbage collection für die verwiesen vars.
Einer vielleicht genauer zu betrachten, Verschlüsse, ist, dass die innere Funktion ist im Grunde verwendet der innere Umfang wie Ihren eigenen Bereich foudnation.
Aber der Zusammenhang verwiesen wird, ist in der Tat hartnäckig, nicht wie eine Momentaufnahme. Immer wieder feuern eines zurückgegebenen innere Funktion, hält Inkrementieren und Protokollierung einer äußeren Funktion lokalen var halten Alarmierung höhere Werte.
InformationsquelleAutor der Antwort Erik Reppen
Sind Sie beide Verschlüsse.
Ich 'm gehen mit der Wikipedia-definition hier:
Dein Freund Versuch deutlich wird, der diese variable
i
das ist nicht lokal, indem Sie seinen Wert ein und machen Sie eine Kopie speichern in die lokalei2
.Ihren eigenen Versuch geht
i
(die auf der call-Seite ist im Umfang), um eine anonyme Funktion, die als argument. Dies ist nicht eine Schließung, so weit, aber dann, die Funktion gibt eine weitere Funktion, die auf die gleichei2
. Da im inneren die innere anonyme Funktioni2
ist nicht eine lokale, schafft dies eine Schließung.InformationsquelleAutor der Antwort Jon
Du und dein Freund beide Verschlüsse:
In Ihrem Freundes-code-Funktion
function(){ console.log(i2); }
definiert im inneren Schließung der anonymen Funktionfunction(){ var i2 = i; ...
und können Lesen/schreiben der lokalen variablei2
.In Ihrer code-Funktion
function(){ console.log(i2); }
definiert im inneren Verschluss der Funktionfunction(i2){ return ...
und können Lesen/schreiben lokaler wertvollei2
(in diesem Fall deklariert als parameter).In beiden Fällen Funktion
function(){ console.log(i2); }
dann ging Sie insetTimeout
.Anderen gleichwertigen (aber mit weniger Speicher Auslastung):
InformationsquelleAutor der Antwort Andrew D.
Schließung
Verschluss ist nicht eine Funktion, und nicht ein Ausdruck. Es muss gesehen werden als eine Art 'Schnappschuss' von den verwendeten Variablen außerhalb der functionscope und innerhalb der Funktion verwendet wird. Grammatikalisch sollte man sagen: "nehmen Sie die Schließung der Variablen'.
Wieder, in anderen Worten: Eine closure ist eine Kopie von den relevanten Kontext der Variablen, auf denen die Funktion abhängt.
Einmal mehr (kehren naive): Eine Schließung ist mit Zugriff auf Variablen, die nicht als parameter übergeben.
Beachten Sie, dass diese funktionale Konzepte hängt stark von der Programmiersprache /- Umgebung Sie verwenden. In JavaScript, die Schließung hängt von lexikalischen scoping (was wahr ist in den meisten c-Sprachen).
So, die RÜCKFÜHRUNG einer Funktion ist meist der Rückkehr eine anonyme /Unbenannte Funktion. Wenn die Funktion auf Variablen zuzugreifen, die nicht als parameter übergeben und innerhalb der (lexikalischen) Umfang, einen Verschluss getroffen wurde.
So, in Bezug auf Ihre Beispiele:
Alle Verschlüsse. Verwechseln Sie nicht die Punkt-Ausführung mit Verschlüssen. Wenn die 'Momentaufnahme' der Verschlüsse auf der falschen moment, können die Werte unerwartete, aber sicherlich ein Verschluss genommen!
InformationsquelleAutor der Antwort Andries
Schauen wir uns beide Möglichkeiten:
Erklärt und führt sofort eine anonyme Funktion, die ausgeführt wird
setTimeout()
in seinem eigenen Kontext. Der aktuelle Wert voni
beibehalten, indem Sie eine Kopie ini2
ersten; es funktioniert, weil die unmittelbare Ausführung.Erklärt ein Ausführungskontext für die innere Funktion, wobei der aktuelle Wert von
i
ist erhalten ini2
; dieser Ansatz nutzt auch die sofortige Ausführung zu erhalten die Wert.Wichtig
Sollte erwähnt werden, dass die run-Semantik sind NICHT die gleichen zwischen den beiden Ansätzen; Ihre innere Funktion übergeben bekommt, um
setTimeout()
in der Erwägung, dass seine innere Funktion ruftsetTimeout()
selbst.Wickeln beide codes in einem anderen
setTimeout()
nicht beweisen, dass nur der zweite Ansatz verwendet die Verschlüsse, es ist einfach nicht die gleiche Sache, um mit zu beginnen.Abschluss
Beide Methoden verwenden, Verschlüsse, so kommt es auf den persönlichen Geschmack; der zweite Ansatz ist einfacher zu "verschieben" um oder verallgemeinern.
InformationsquelleAutor der Antwort Ja͢ck
Ich schrieb vor einer Weile, mich daran zu erinnern, was für ein Verschluss ist und wie es funktioniert in JS.
Eine closure ist eine Funktion, die, wenn Sie aufgerufen wird, verwendet der Bereich, in dem es deklariert wurde, wird nicht der Umfang, in dem es aufgerufen wurde. In javaScript sind alle Funktionen Verhalten sich wie diese. Variable Werte in einem Umfang bestehen, solange es eine Funktion gibt, die noch Punkte. Die Ausnahme von der Regel ist 'dies' bezieht sich auf das Objekt, dass die Funktion im inneren, wenn es aufgerufen wird.
InformationsquelleAutor der Antwort Nat Darke
Nach der Inspektion eng, sieht aus wie Sie beide sind mit Verschluss.
In Ihre Freunde Fall
i
zugegriffen innere anonyme Funktion 1 undi2
zugegriffen wird, in eine anonyme Funktion 2, wo dieconsole.log
vorhanden ist.In Ihrem Fall, auf den Sie zugreifen
i2
innere anonyme Funktion, woconsole.log
vorhanden ist. Hinzufügen einesdebugger;
Anweisung vorconsole.log
und in den chrome developer tools unter "Geltungsbereich von Variablen" wird es Ihnen sagen, unter welchen Gültigkeitsbereich der variable ist.InformationsquelleAutor der Antwort Ramesh
Ich würde gerne meine Beispiel und eine Erklärung über Verschlüsse. Ich machte ein python-Beispiel, und zwei Figuren, um zu demonstrieren, stack-Staaten.
Die Ausgabe dieses Codes würde wie folgt Aussehen:
Hier sind zwei zahlen, um zu zeigen, stacks und der Verschluss angebracht, um den function-Objekt.
wenn die Funktion zurückgibt maker
wenn die Funktion aufgerufen wird später
Wenn die Funktion aufgerufen wird durch einen parameter oder eine nichtlokale variable, der code muss lokale Variablen wie margin_top, Polsterung sowie eine, b, n. Um sicherzustellen, dass die Funktion code zu arbeiten, der stack-frame der maker-Funktion, die war fortgegangen, vor langer Zeit zugänglich sein sollte, was ist gesichert in der Schließung können wir, zusammen mit der Funktion message-Objekt.
InformationsquelleAutor der Antwort Eunjung Lee