Hin und wieder werden „Verschlüsse“ erwähnt, und ich habe versucht, sie nachzuschlagen, aber das Wiki gibt keine Erklärung, die ich verstehe. Könnte jemand Helfen Sie mir hier raus?
Kommentare
- Wenn Sie Java / C # kennen, hoffen Sie, dass dieser Link hilft- http://www.developerfusion.com/article/8251/the-beauty-of-closures/
- Verschlüsse sind schwer zu verstehen. Sie sollten versuchen, auf alle Links im ersten Satz dieses Wikipedia-Artikels zu klicken und diese zu verstehen Artikel zuerst.
- stackoverflow.com/questions/36636/what-is-a-closure
- Was ‚ ist der grundlegende Unterschied zwischen einem Abschluss und einer Klasse? Okay, eine Klasse mit nur einer öffentlichen Methode.
- @biziclop: Sie könnten Ich emuliere einen Abschluss mit einer Klasse (das ‚ ist das, was Java-Entwickler tun müssen). Aber sie ‚ sind normalerweise etwas weniger ausführlich zu erstellen und Sie nicht muss nicht manuell verwalten, was Sie ‚ tun. (Die Hardcore-Lisper stellen eine ähnliche Frage, kommen aber wahrscheinlich zu dieser anderen Schlussfolgerung – dass OO-Unterstützung auf Sprachebene nicht erforderlich ist, wenn Sie Schließungen haben.)
Antwort
(Haftungsausschluss: Dies ist eine grundlegende Erklärung; soweit die Definition reicht, vereinfache ich ein wenig)
Die einfachste Art, sich einen Abschluss vorzustellen, ist eine -Funktion, die als Variable (als „first“ bezeichnet werden kann) gespeichert werden kann -class function „), die eine spezielle Fähigkeit hat, auf andere Variablen zuzugreifen, die lokal für den Bereich sind, in dem sie erstellt wurden.
Beispiel (JavaScript):
var setKeyPress = function(callback) { document.onkeypress = callback; }; var initialize = function() { var black = false; document.onclick = function() { black = !black; document.body.style.backgroundColor = black ? "#000000" : "transparent"; } var displayValOfBlack = function() { alert(black); } setKeyPress(displayValOfBlack); }; initialize();
Die Funktionen 1 , die document.onclick
und displayValOfBlack
sind Abschlüsse. Sie können sehen, dass beide auf die boolesche Variable black
verweisen, diese Variable jedoch außerhalb der Funktion zugewiesen wird. Weil black
ist lokal für den Bereich, in dem die Funktion definiert wurde , der Zeiger auf diese Variable bleibt erhalten.
Wenn Sie dies in eine HTML-Seite einfügen:
- Klicken Sie hier, um in Schwarz zu wechseln.
- Drücken Sie die [Eingabetaste], um „true“ anzuzeigen > Drücken Sie die [Eingabetaste], um „false“ anzuzeigen.
Dies zeigt, dass beide Zugriff auf dasselbe black
haben. und kann verwendet werden, um den Status ohne Wrapper-Objekt zu speichern.
Der Aufruf von setKeyPress
soll demonstrieren, wie eine Funktion übergeben werden kann genau wie jede Variable. Der im Abschluss erhaltene Bereich ist immer noch derjenige, in dem die Funktion definiert wurde.
Schließungen sind häufig Wird als Ereignishandler verwendet, insbesondere in JavaScript und ActionScript. Durch die gute Verwendung von Closures können Sie Variablen implizit an Ereignishandler binden, ohne einen Objekt-Wrapper erstellen zu müssen. Eine unachtsame Verwendung führt jedoch zu Speicherverlusten (z. B. wenn nur ein nicht verwendeter, aber erhaltener Ereignishandler große Objekte im Speicher, insbesondere DOM-Objekte, festhält und die Speicherbereinigung verhindert).
1: Tatsächlich sind alle Funktionen in JavaScript Abschlüsse.
Kommentare
- Als ich Ihre Antwort las, habe ich Ich spürte, wie sich eine Glühbirne in meinem Kopf einschaltete. Sehr geschätzt! 🙂
- Da
black
in einer Funktion deklariert ist, werden ‚ nicht zerstört, wenn der Stapel abgewickelt wird. ..? - @gablin, das ist das Besondere an Sprachen mit Verschlüssen. Alle Sprachen mit Garbage Collection funktionieren ähnlich – wenn keine Verweise mehr auf ein Objekt gespeichert sind, kann es zerstört werden. Immer wenn eine Funktion in JS erstellt wird, ist der lokale Bereich an diese Funktion gebunden, bis diese Funktion zerstört wird.
- @gablin, ‚ ist eine gute Frage. Ich ‚ glaube nicht, dass sie ‚ t & können mdash; Aber ich habe nur die Garbage Collection aufgerufen, seitdem JS das verwendet und ‚ das ist, worauf Sie sich zu beziehen schienen, als Sie “ seither sagten
black
wird innerhalb einer Funktion deklariert, würde nicht ‚ nicht zerstört werden „. Denken Sie auch daran, dass, wenn Sie ein Objekt in einer Funktion deklarieren und es dann einer Variablen zuweisen, die an einer anderen Stelle lebt, dieses Objekt erhalten bleibt, da andere Verweise darauf vorhanden sind. - Objective-C (und C under clang) unterstützt Blöcke, die im Wesentlichen Verschlüsse sind, ohne Speicherbereinigung. Es erfordert Laufzeitunterstützung und einige manuelle Eingriffe in die Speicherverwaltung.
Antwort
Ein Abschluss ist im Grunde nur eine andere Sichtweise auf ein Objekt. Ein Objekt sind Daten, an die eine oder mehrere Funktionen gebunden sind. Ein Abschluss ist eine Funktion, an die eine oder mehrere Variablen gebunden sind. Die beiden sind grundsätzlich identisch, zumindest auf Implementierungsebene. Der eigentliche Unterschied besteht darin, woher sie stammen.
Bei der objektorientierten Programmierung deklarieren Sie eine Objektklasse, indem Sie ihre Elementvariablen und ihre Methoden (Elementfunktionen) im Voraus definieren und anschließend Instanzen von erstellen diese Klasse. Jede Instanz enthält eine Kopie der Mitgliedsdaten, die vom Konstruktor initialisiert wurden. Sie haben dann eine Variable eines Objekttyps und geben sie als Datenelement weiter, da der Fokus auf ihrer Natur als Daten liegt.
In einem Abschluss hingegen ist das Objekt nicht im Voraus wie eine Objektklasse definiert oder durch einen Konstruktoraufruf in Ihrem Code instanziiert. Stattdessen schreiben Sie den Abschluss als Funktion in eine andere Funktion. Der Abschluss kann sich auf eine der lokalen Variablen der äußeren Funktion beziehen, und der Compiler erkennt dies und verschiebt diese Variablen aus dem Stapelbereich der äußeren Funktion in die Deklaration für versteckte Objekte des Abschlusses. Sie haben dann eine Variable eines Schließungstyps und obwohl es sich im Grunde genommen um ein Objekt unter der Haube handelt, geben Sie es als Funktionsreferenz weiter, da der Fokus auf seiner Natur als Funktion liegt.
Kommentare
- +1: Gute Antwort. Sie können einen Abschluss als Objekt mit nur einer Methode und ein beliebiges Objekt als Sammlung von Abschlüssen über einige gemeinsame zugrunde liegende Daten (die Mitgliedsvariablen des Objekts ‚) sehen. Ich denke, diese beiden Ansichten sind ziemlich symmetrisch.
- Sehr gute Antwort. Es erklärt tatsächlich die Einsicht der Schließung.
- @Mason Wheeler: Wo werden Schließungsdaten gespeichert? Im Stapel wie eine Funktion? Oder im Heap wie ein Objekt?
- @RoboAlex: Im Heap, weil es ‚ ein Objekt ist, das wie eine Funktion aussieht
- @RoboAlex: Wo ein Abschluss und seine erfassten Daten gespeichert werden, hängt von der Implementierung ab. In C ++ kann es im Heap oder auf dem Stapel gespeichert werden.
Antwort
Der Begriff Schließung beruht auf der Tatsache, dass ein Code (Block, Funktion) freie Variablen haben kann, die (dh an einen Wert gebunden) von der Umgebung geschlossen, in der der Codeblock definiert ist.
Nehmen Sie zum Beispiel die Scala-Funktionsdefinition :
def addConstant(v: Int): Int = v + k
Im Funktionskörper gibt es zwei Namen (Variablen) v
und k
gibt zwei ganzzahlige Werte an. Der Name v
ist gebunden, da er als Argument der Funktion addConstant
deklariert ist (wenn wir uns die Funktionsdeklaration ansehen, wissen wir, dass v
wird beim Aufrufen der Funktion ein Wert zugewiesen). Der Name k
ist für die Funktion addConstant
frei, da die Funktion keinen Hinweis darauf enthält, welcher Wert k
ist an (und wie) gebunden.
Um einen Anruf wie folgt auszuwerten:
val n = addConstant(10)
müssen wir k
ein Wert, der nur auftreten kann, wenn der Name k
in dem Kontext definiert ist, in dem addConstant
ist definiert. Zum Beispiel:
def increaseAll(values: List[Int]): List[Int] = { val k = 2 def addConstant(v: Int): Int = v + k values.map(addConstant) }
Nachdem wir addConstant
in einem Kontext definiert haben, in dem k
ist definiert, addConstant
ist zu einem Abschluss geworden, weil alle Die freien Variablen sind jetzt geschlossen (an einen Wert gebunden): addConstant
can aufgerufen und weitergegeben werden, als wäre es eine Funktion. Beachten Sie, dass die freie Variable k
an einen Wert gebunden ist, wenn der Abschluss definiert ist , während die Argumentvariable v
gebunden ist, wenn der Abschluss aufgerufen wird.
Ein Abschluss ist also im Grunde eine Funktion oder ein Codeblock, der über seine freien Variablen auf nicht lokale Werte zugreifen kann, nachdem diese durch den Kontext gebunden wurden.
In vielen Sprachen, wenn Sie Verwenden Sie einen Abschluss nur, wenn Sie ihn anonym machen können, z. B.
def increaseAll(values: List[Int]): List[Int] = { val k = 2 values.map(v => v + k) }
Beachten Sie, dass eine Funktion ohne freie Variablen ein Sonderfall eines Abschlusses ist (mit einem leeren Satz freier Variablen). Analog ist eine anonyme Funktion ein Sonderfall eines anonymen Abschlusses , dh eine anonyme Funktion ist ein anonymer Abschluss ohne freie Variablen.
Kommentare
- Dies passt gut zu geschlossenen und offenen Formeln in der Logik. Vielen Dank für Ihre Antwort.
- @RainDoctor: Freie Variablen werden in Logikformeln und in Lambda-Kalkülausdrücken auf ähnliche Weise definiert: Das Lambda in einem Lambda-Ausdruck funktioniert wie ein Quantifizierer in Logikformeln für freie / gebundene Variablen .
Antwort
Eine einfache Erklärung in JavaScript:
var closure_example = function() { var closure = 0; // after first iteration the value will not be erased from the memory // because it is bound with the returned alertValue function. return { alertValue : function() { closure++; alert(closure); } }; }; closure_example();
alert(closure)
verwendet den zuvor erstellten Wert von closure
. Der Namespace der zurückgegebenen Funktion alertValue
wird mit dem Namespace verbunden, in dem sich die Variable closure
befindet. Wenn Sie die gesamte Funktion löschen, wird die Der Wert der Variablen closure
wird gelöscht. Bis dahin kann die Funktion alertValue
den Wert der Variablen immer lesen / schreiben closure
.
Wenn Sie diesen Code ausführen, weist die erste Iteration der Variablen closure
und einen Wert 0 zu Schreiben Sie die Funktion wie folgt um:
var closure_example = function(){ alertValue : function(){ closure++; alert(closure); } }
Und weil alertValue
die lokale Variable closure
Um die Funktion auszuführen, bindet sie sich an den Wert der zuvor zugewiesenen lokalen Variablen closure
.
Und jetzt jedes Mal, wenn Sie die closure_example
-Funktion schreibt den inkrementierten Wert der Variablen closure
aus, da alert(closure)
ist gebunden.
closure_example.alertValue()//alerts value 1 closure_example.alertValue()//alerts value 2 closure_example.alertValue()//alerts value 3 //etc.
Kommentare
- Danke, ich habe nicht ‚ t test the code =) Jetzt scheint alles in Ordnung zu sein.
Antwort
Ein „Abschluss“ ist Im Wesentlichen ein lokaler Status und ein Code, die zu einem Paket zusammengefasst sind. Normalerweise stammt der lokale Status aus einem umgebenden (lexikalischen) Bereich, und der Code ist (im Wesentlichen) eine innere Funktion, die dann nach außen zurückgegeben wird. Der Abschluss ist dann eine Kombination aus den erfassten Variablen, die die innere Funktion sieht, und dem Code der inneren Funktion.
Es ist eines dieser Dinge, das aufgrund dessen leider etwas schwer zu erklären ist Unbekannt sein.
Eine Analogie, die ich in der Vergangenheit erfolgreich verwendet habe, war „Stellen Sie sich vor, wir haben etwas, das wir“ das Buch „nennen. In der Raumschließung ist“ das Buch „die Kopie dort drüben in der Ecke , von TAOCP, aber auf dem Tabellenabschluss ist es die Kopie eines Dresdner Aktenbuchs. Je nachdem, in welchem Abschluss Sie sich befinden, führt der Code „Gib mir das Buch“ dazu, dass verschiedene Dinge passieren. „
Kommentare
- Sie haben dies vergessen: en.wikipedia.org/wiki/Closure_(computer_programming) in Ihrer Antwort.
- Nein, ich habe mich bewusst dafür entschieden, diese Seite nicht zu schließen.
- “ Status und Funktion. „: Kann eine C-Funktion mit einer
static
lokalen Variablen als Abschluss betrachtet werden? in Haskell involvieren Zustand? - @Giorgio Closures in Haskell schließen (glaube ich) über die Argumente in dem lexikalischen Bereich, in dem sie ‚ definiert sind, also ich ‚ würde sagen “ ja “ (obwohl ich Haskell bestenfalls nicht kenne). Eine AC-Funktion mit einer statischen Variablen ist bestenfalls ein sehr begrenzter Abschluss (Sie möchten wirklich in der Lage sein, mehrere Abschlüsse aus einer einzigen Funktion mit einer lokalen Variablen
static
zu erstellen genau eine). - Ich habe diese Frage absichtlich gestellt, weil ich denke, dass eine C-Funktion mit einer statischen Variablen kein Abschluss ist: Die statische Variable ist lokal definiert und nur innerhalb des Abschlusses bekannt, sie greift nicht zu die Umgebung. Ich bin mir auch nicht 100% sicher, aber ich würde Ihre Aussage umgekehrt formulieren: Sie verwenden den Schließungsmechanismus, um verschiedene Funktionen zu erstellen (eine Funktion ist eine Schließungsdefinition + eine Bindung für ihre freien Variablen).
Antwort
Es ist schwer zu definieren, was ein Abschluss ist, ohne das Konzept des „Zustands“ zu definieren.
Grundsätzlich In einer Sprache mit vollständigem lexikalischem Umfang, in der Funktionen als erstklassige Werte behandelt werden, geschieht etwas Besonderes. Wenn ich etwas tun würde wie:
function foo(x) return x end x = foo
Die Variable x
verweist nicht nur auf function foo()
verweist aber auch auf den Status foo
, der bei der letzten Rückkehr verlassen wurde. Die wahre Magie entsteht, wenn foo
andere Funktionen in seinem Bereich weiter definiert hat; Es ist wie eine eigene Mini-Umgebung (genau wie „normal“ definieren wir Funktionen in einer globalen Umgebung).
Funktionell kann es viele der gleichen Probleme lösen wie C ++ (C?) „s“ statisches „Schlüsselwort, das den Status einer lokalen Variablen während mehrerer Funktionsaufrufe beibehält; Es ist jedoch eher so, als würde man dasselbe Prinzip (statische Variable) auf eine Funktion anwenden, da Funktionen erstklassige Werte sind. Durch das Schließen wird der zu speichernde Status der gesamten Funktion unterstützt (nichts mit den statischen Funktionen von C ++ zu tun).
Wenn Sie Funktionen als erstklassige Werte behandeln und Unterstützung für Schließungen hinzufügen, können Sie auch mehr als eine Instanz derselben Funktion im Speicher haben (ähnlich wie bei Klassen). Dies bedeutet, dass Sie die Funktion wiederverwenden können Derselbe Code, ohne dass der Status der Funktion zurückgesetzt werden muss, wie er beim Umgang mit statischen C ++ – Variablen innerhalb einer Funktion erforderlich ist (kann diesbezüglich falsch sein?).
Hier einige Tests zur Unterstützung der Schließung von Lua
--Closure testing --By Trae Barlow -- function myclosure() print(pvalue)--nil local pvalue = pvalue or 10 return function() pvalue = pvalue + 10 --20, 31, 42, 53(53 never printed) print(pvalue) pvalue = pvalue + 1 --21, 32, 43(pvalue state saved through multiple calls) return pvalue end end x = myclosure() --x now references anonymous function inside myclosure() x()--nil, 20 x() --21, 31 x() --32, 42 --43, 53 -- if we iterated x() again
Ergebnisse:
nil 20 31 42
Es kann schwierig werden und es variiert wahrscheinlich von Sprache zu Sprache, aber es scheint in Lua, dass bei jeder Ausführung einer Funktion ihr Status zurückgesetzt wird. Ich sage dies, weil die Ergebnisse des obigen Codes unterschiedlich wären, wenn wir auf die Funktion / Zustand direkt (anstelle der anonymen Funktion, die zurückgegeben wird), da pvalue
auf 10 zurückgesetzt würde; Wenn wir jedoch über x (die anonyme Funktion) auf den Status von myclosure zugreifen, können Sie sehen, dass pvalue
lebt und sich irgendwo im Speicher befindet. Ich vermute, dass möglicherweise etwas mehr dahinter steckt Jemand kann die Art der Implementierung besser erklären.
PS: Ich kenne kein C ++ 11-Leck (außer dem, was in früheren Versionen enthalten ist). Beachten Sie daher, dass dies kein Vergleich ist zwischen Schließungen in C ++ 11 und Lua. Außerdem sind alle von Lua nach C ++ gezogenen „Linien“ Ähnlichkeiten, da statische Variablen und Verschlüsse nicht zu 100% gleich sind. selbst wenn sie manchmal verwendet werden, um ähnliche Probleme zu lösen.
Ich bin mir nicht sicher, ob im obigen Codebeispiel die anonyme Funktion oder die Funktion höherer Ordnung als Abschluss betrachtet wird?
Antwort
Ein Abschluss ist eine Funktion, der der Status zugeordnet ist:
In Perl erstellen Sie Abschlüsse wie folgt:
#!/usr/bin/perl # This function creates a closure. sub getHelloPrint { # Bind state for the function we are returning. my ($first) = @_;a # The function returned will have access to the variable $first return sub { my ($second) = @_; print "$first $second\n"; }; } my $hw = getHelloPrint("Hello"); my $gw = getHelloPrint("Goodby"); &$hw("World"); // Print Hello World &$gw("World"); // PRint Goodby World
Wenn wir uns die neue Funktionalität von C ++ ansehen.
Sie können damit auch den aktuellen Status an das Objekt binden:
#include <string> #include <iostream> #include <functional> std::function<void(std::string const&)> getLambda(std::string const& first) { // Here we bind `first` to the function // The second parameter will be passed when we call the function return [first](std::string const& second) -> void { std::cout << first << " " << second << "\n"; }; } int main(int argc, char* argv[]) { auto hw = getLambda("Hello"); auto gw = getLambda("GoodBye"); hw("World"); gw("World"); }
Antwort
Betrachten wir eine einfache Funktion:
function f1(x) { // ... something }
Diese Funktion wird als Funktion der obersten Ebene bezeichnet, da sie in keiner anderen Funktion verschachtelt ist. Jede Die JavaScript-Funktion ordnet sich eine Liste von Objekten zu, die als “ Scope Chain „ bezeichnet werden. Diese Scope-Kette ist eine geordnete Liste von Objekten. E. Jedes dieser Objekte definiert einige Variablen.
In Funktionen der obersten Ebene besteht die Bereichskette aus einem einzelnen Objekt, dem globalen Objekt. Die obige Funktion f1
enthält beispielsweise eine Bereichskette mit einem einzelnen Objekt, das alle globalen Variablen definiert. (Beachten Sie, dass der Begriff „Objekt“ hier kein JavaScript-Objekt bedeutet, sondern lediglich ein implementierungsdefiniertes Objekt, das als Variablencontainer fungiert, in dem JavaScript Variablen „nachschlagen“ kann.)
Wenn dies der Fall ist Wenn die Funktion aufgerufen wird, erstellt JavaScript ein so genanntes „Aktivierungsobjekt“ und setzt es an die Spitze der Bereichskette Das Objekt enthält alle lokalen Variablen (zum Beispiel x
hier). Daher haben wir jetzt zwei Objekte in der Bereichskette: Das erste ist das Aktivierungsobjekt und darunter das globale Objekt.
Beachten Sie sehr sorgfältig, dass die beiden Objekte zu VERSCHIEDENEN Zeiten in die Gültigkeitsbereichskette eingefügt werden. Das globale Objekt wird eingefügt, wenn die Funktion definiert wird (dh wenn JavaScript die Funktion analysiert und das Funktionsobjekt erstellt hat) Das Aktivierungsobjekt wird beim Aufrufen der Funktion eingegeben.
Nun wissen wir Folgendes:
- Jeder Funktion ist eine Bereichskette zugeordnet.
- WannWenn die Funktion definiert ist (wenn das Funktionsobjekt erstellt wird), speichert JavaScript eine Bereichskette mit dieser Funktion.
- Bei Funktionen der obersten Ebene enthält die Bereichskette zum Zeitpunkt der Funktionsdefinition nur das globale Objekt und fügt ein zusätzliches hinzu Aktivierungsobjekt oben beim Aufruf
Die Situation wird interessant, wenn wir uns mit verschachtelten Funktionen befassen. Erstellen wir also eine:
function f1(x) { function f2(y) { // ... something } }
Wenn f1
definiert wird, erhalten wir eine Bereichskette dafür Nur das globale Objekt.
Wenn nun f1
aufgerufen wird, erhält die Bereichskette von f1
das Aktivierungsobjekt. Dieses Aktivierungsobjekt enthält die Variable x
und die Variable f2
, die eine Funktion ist. Beachten Sie außerdem, dass f2
wird definiert.Daher speichert JavaScript zu diesem Zeitpunkt auch eine neue Bereichskette für f2
. Die für diese innere Funktion gespeicherte Bereichskette ist die aktuell gültige Bereichskette. Der aktuelle Bereich Kette in der Tat ist die von f1
„s. Daher ist die Bereichskette von f2
“ f1
„s aktuelle Bereichskette – enthält das Aktivierungsobjekt von f1
und das globale Objekt.
Wenn f2
aufgerufen wird, erhält es sein eigenes Aktivierungsobjekt, das y
, hinzugefügt zu seiner Bereichskette, die bereits das Aktivierungsobjekt von f1
und das globale Objekt enthält.
Wenn in f2
, seine Gültigkeitsbereichskette würde zur Definitionszeit drei Objekte enthalten (2 Aktivierungsobjekte mit zwei äußeren Funktionen und das globale Objekt) und 4 zum Aufrufzeitpunkt.
Also, jetzt verstehen wir und wie die Bereichskette funktioniert, aber wir haben noch nicht über Schließungen gesprochen.
Die Kombination eines Funktionsobjekts und eines Bereichs (eine Reihe von Variablenbindungen) in dem die Variablen der Funktion aufgelöst werden, wird in der Informatikliteratur als Abschluss bezeichnet – JavaScript der endgültige Leitfaden von David Flanagan
Die meisten Funktionen werden mit derselben Bereichskette aufgerufen, die zum Zeitpunkt der Definition der Funktion gültig war, und es spielt keine Rolle, ob es sich um einen Abschluss handelt. Abschlüsse werden interessant, wenn sie unter einer anderen Gültigkeitsbereichskette aufgerufen werden als die, die zum Zeitpunkt ihrer Definition gültig war. Dies geschieht am häufigsten, wenn ein verschachteltes Funktionsobjekt von der Funktion zurückgegeben wird, in der es definiert wurde.
Wenn die Funktion zurückkehrt, wird dieses Aktivierungsobjekt aus der Bereichskette entfernt. Wenn keine verschachtelten Funktionen vorhanden waren, gibt es keine Verweise mehr auf das Aktivierungsobjekt und es wird Müll gesammelt. Wenn verschachtelte Funktionen definiert wurden, hat jede dieser Funktionen einen Verweis auf die Bereichskette, und diese Bereichskette bezieht sich auf das Aktivierungsobjekt.
Wenn diese verschachtelten Funktionsobjekte jedoch innerhalb ihrer äußeren Funktion blieben dann werden sie selbst zusammen mit dem Aktivierungsobjekt, auf das sie sich beziehen, mit Müll gesammelt. Wenn die Funktion jedoch eine verschachtelte Funktion definiert und sie zurückgibt oder irgendwo in einer Eigenschaft speichert, gibt es einen externen Verweis auf die verschachtelte Funktion. Es wird kein Müll gesammelt, und das Aktivierungsobjekt, auf das es sich bezieht, wird auch nicht gesammelt.
In unserem obigen Beispiel geben wir f2
von f1
Wenn daher ein Aufruf von f1
zurückgegeben wird, wird das Aktivierungsobjekt aus der Bereichskette entfernt und der Müll gesammelt. Aber wenn wir so etwas hätten:
function f1(x) { function f2(y) { // ... something } return f2; }
Hier hat die zurückkehrende f2
eine Bereichskette, die dies ermöglicht Enthält das Aktivierungsobjekt von f1
, und daher wird kein Müll gesammelt. Wenn wir zu diesem Zeitpunkt f2
aufrufen, kann es auf die Variable f1
„x
obwohl wir uns außerhalb von f1
befinden.
Daher können wir sehen, dass eine Funktion die Gültigkeitsbereichskette mit ihr und mit der Bereichskette beibehält Es kommen alle Aktivierungsobjekte der äußeren Funktionen. Dies ist die Essenz des Abschlusses. Wir sagen, dass Funktionen in JavaScript „lexikalisch“ , was bedeutet, dass sie den Bereich speichern, der aktiv war, als sie definiert wurden, im Gegensatz zu dem Bereich, der aktiv war, als sie aufgerufen wurden.
Es gibt eine Reihe leistungsfähiger Programmiertechniken, die Abschlüsse wie die Approximation privater Variablen beinhalten , ereignisgesteuerte Programmierung, Teilanwendung usw.
Beachten Sie auch, dass all dies für alle Sprachen gilt, die das Schließen unterstützen. Zum Beispiel PHP (5.3+), Python, Ruby usw.
Antwort
Ein Abschluss ist eine Compileroptimierung (auch bekannt als syntaktischer Zucker?). Einige Leute haben dies auch als Objekt des armen Mannes bezeichnet.
Siehe die Antwort von Eric Lippert : (Auszug unten)
Der Compiler generiert Code wie folgt:
private class Locals { public int count; public void Anonymous() { this.count++; } } public Action Counter() { Locals locals = new Locals(); locals.count = 0; Action counter = new Action(locals.Anonymous); return counter; }
Sinnvoll?
Außerdem haben Sie nach Vergleichen gefragt. VB und JScript erstellen beide Abschlüsse auf die gleiche Weise.
Kommentare
- Diese Antwort ist eine CW, da ich ‚ keine Punkte für Eric ‚ s großartige Antwort.Bitte stimmen Sie es nach Belieben ab. HTH
- -1: Ihre Erklärung ist in C # zu tief verwurzelt. Closure wird in vielen Sprachen verwendet und ist in diesen Sprachen viel mehr als syntaktischer Zucker und umfasst sowohl die Funktion als auch den Zustand.
- Nein, ein Closure ist weder nur ein “ Compileroptimierung “ noch syntaktischer Zucker. -1