Vielleicht ein wenig über alle, aber die frühreifsten der Sechsjährigen, aber ein paar Beispiele, die dazu beigetragen, dass das Konzept der Schließung in JavaScript Klick für mich.
Eine Schließung ist eine Funktion, die Zugriff auf den Geltungsbereich einer anderen Funktion (ihre Variablen und Funktionen) hat. Der einfachste Weg, eine Closure zu erstellen, ist eine Funktion innerhalb einer Funktion; der Grund dafür ist, dass in JavaScript eine Funktion immer Zugriff auf den Bereich der sie enthaltenden Funktion hat.
function outerFunction() {
var outerVar = "monkey";
function innerFunction() {
alert(outerVar);
}
innerFunction();
}
outerFunction();
ALERT: Affe
Im obigen Beispiel wird outerFunction aufgerufen, die wiederum innerFunction aufruft. Man beachte, dass outerVar für innerFunction verfügbar ist, was dadurch belegt wird, dass der Wert von outerVar korrekt gemeldet wird.
Überlegen Sie nun Folgendes:
function outerFunction() {
var outerVar = "monkey";
function innerFunction() {
return outerVar;
}
return innerFunction;
}
var referenceToInnerFunction = outerFunction();
alert(referenceToInnerFunction());
ALERT: Affe
referenceToInnerFunction wird auf outerFunction() gesetzt, die einfach einen Verweis auf innerFunction zurückgibt. Wenn referenceToInnerFunction aufgerufen wird, gibt es outerVar zurück. Auch hier zeigt sich wieder, dass innerFunction Zugriff auf outerVar, eine Variable von outerFunction, hat. Interessant ist auch, dass sie diesen Zugriff auch nach Beendigung der Ausführung von outerFunction beibehält.
Und hier wird es wirklich interessant. Wenn wir outerFunction loswerden, sagen wir, es auf null setzen, könnte man meinen, dass referenceToInnerFunction seinen Zugriff auf den Wert von outerVar verlieren würde. Aber das ist nicht der Fall.
function outerFunction() {
var outerVar = "monkey";
function innerFunction() {
return outerVar;
}
return innerFunction;
}
var referenceToInnerFunction = outerFunction();
alert(referenceToInnerFunction());
outerFunction = null;
alert(referenceToInnerFunction());
ALERT: Affe ALERT: Affe
Aber warum ist das so? Wie kann referenceToInnerFunction immer noch den Wert von outerVar kennen, nachdem outerFunction auf null gesetzt wurde?
Der Grund dafür, dass referenceToInnerFunction immer noch auf den Wert von outerVar zugreifen kann, liegt darin, dass innerFunction bei der ersten Erstellung der Closure durch Platzierung von innerFunction innerhalb von outerFunction einen Verweis auf den Bereich von outerFunction (seine Variablen und Funktionen) zu seiner Bereichskette hinzugefügt hat. Das bedeutet, dass innerFunction einen Zeiger oder Verweis auf alle Variablen von outerFunction hat, einschließlich outerVar. Selbst wenn die Ausführung von outerFunction beendet ist oder wenn sie gelöscht oder auf null gesetzt wird, verbleiben die Variablen in ihrem Bereich, wie outerVar, im Speicher, da der Verweis auf sie auf Seiten der innerFunction, die an referenceToInnerFunction zurückgegeben wurde, noch aussteht. Um outerVar und die übrigen Variablen von outerFunction wirklich aus dem Speicher freizugeben, müssten Sie diesen ausstehenden Verweis auf sie loswerden, indem Sie beispielsweise referenceToInnerFunction ebenfalls auf null setzen.
//////////
Zwei weitere Dinge zu den Schließungen sind zu beachten. Erstens hat die Schließung immer Zugriff auf die letzten Werte der sie enthaltenden Funktion.
function outerFunction() {
var outerVar = "monkey";
function innerFunction() {
alert(outerVar);
}
outerVar = "gorilla";
innerFunction();
}
outerFunction();
ALERT: Gorilla
Zweitens behält eine Closure bei ihrer Erstellung einen Verweis auf alle Variablen und Funktionen der sie umschließenden Funktion bei; sie kann sich nicht alles aussuchen. Daher sollten Closures sparsam oder zumindest vorsichtig eingesetzt werden, da sie sehr speicherintensiv sein können; viele Variablen können noch lange nach der Ausführung einer enthaltenen Funktion im Speicher gehalten werden.