7619 Stimmen

Wie funktionieren die JavaScript-Schließungen?

Wie würden Sie JavaScript-Schließungen jemandem erklären, der zwar die Konzepte kennt, aus denen sie bestehen (z. B. Funktionen, Variablen und Ähnliches), aber die Schließungen selbst nicht versteht?

Ich habe gesehen das Beispiel Schema auf Wikipedia angegeben, aber leider hat es nicht geholfen.

545voto

Konrad Rudolph Punkte 503837

Verschlüsse sind schwer zu erklären, weil sie dazu dienen, ein Verhalten zu erreichen, von dem jeder intuitiv erwartet, dass es funktioniert. Ich finde, der beste Weg, sie zu erklären (und der Weg, den I Sie haben gelernt, was sie tun, indem sie sich die Situation ohne sie vorstellen:

const makePlus = function(x) {
    return function(y) { return x + y; };
}

const plus5 = makePlus(5);
console.log(plus5(3));

Was würde hier passieren, wenn JavaScript hat nicht Schließungen kennen? Ersetzen Sie einfach den Aufruf in der letzten Zeile durch den Methodenrumpf (das ist im Grunde, was Funktionsaufrufe tun) und Sie erhalten:

console.log(x + 3);

Wo ist nun die Definition von x ? Wir haben sie im aktuellen Geltungsbereich nicht definiert. Die einzige Lösung ist, dass wir plus5 tragen seinen Geltungsbereich (oder besser gesagt, den Geltungsbereich seiner Eltern) um. Auf diese Weise, x ist wohldefiniert und an den Wert 5 gebunden.

2 Stimmen

"Sie werden verwendet, um ein Verhalten zum Funktionieren zu bringen, von dem jeder intuitiv erwartet, dass es sowieso funktioniert". Ich hatte das Gefühl, etwas zu übersehen, aber es stellte sich heraus, dass ich es nicht tat!

0 Stimmen

Closure ist nur das Speichern der äußeren lexikalischen Umgebung. Wenn eine Funktion in einer lexikalischen Umgebung erstellt wurde, bedeutet das, dass sie Teil des Speichers dieser lexikalischen Umgebung ist. Wenn ich die Funktion aufrufe, wird ein neuer Ausführungskontext erstellt und eine neue lexikalische Umgebung wird erstellt und ihre äußere Referenz wird auf die lexikalische Umgebung verweisen, in der die Funktion erstellt wurde.

0 Stimmen

@NadavShlush Das ist, was meine Antwort in weniger Worten bereits sagt, ja.

422voto

Florian Bösch Punkte 26702

TLDR

Eine Schließung ist eine Verbindung zwischen einer Funktion und ihrer äußeren lexikalischen (d.h. wie geschrieben) Umgebung, so dass die in dieser Umgebung definierten Bezeichner (Variablen, Parameter, Funktionsdeklarationen usw.) von der Funktion aus sichtbar sind, unabhängig davon, wann oder von wo aus die Funktion aufgerufen wird.

Detalles

In der Terminologie der ECMAScript-Spezifikation kann man sagen, dass eine Schließung durch die [[Environment]] Referenz eines jeden Funktionsobjekts, die auf den lexikalische Umgebung innerhalb derer die Funktion definiert ist.

Wenn eine Funktion über die interne [[Call]] Methode, die [[Environment]] Referenz auf das Funktionsobjekt wird in die Hinweis auf die äußere Umgebung de la Umwelt-Datensatz der neugeschaffenen Ausführungskontext (Stapelrahmen).

Im folgenden Beispiel wird die Funktion f schließt über die lexikalische Umgebung des globalen Ausführungskontexts:

function f() {}

Im folgenden Beispiel wird die Funktion h schließt sich über die lexikalische Umgebung der Funktion g der wiederum die lexikalische Umgebung des globalen Ausführungskontexts abschließt.

function g() {
    function h() {}
}

Wenn eine innere Funktion von einer äußeren Funktion zurückgegeben wird, bleibt die äußere lexikalische Umgebung bestehen, nachdem die äußere Funktion zurückgekehrt ist. Dies liegt daran, dass die äußere lexikalische Umgebung verfügbar sein muss, wenn die innere Funktion schließlich aufgerufen wird.

Im folgenden Beispiel wird die Funktion j schließt sich über die lexikalische Umgebung der Funktion i , was bedeutet, dass die Variable x ist von innerhalb der Funktion sichtbar j , lange nach der Funktion i die Ausführung abgeschlossen hat:

function i() {
    var x = 'mochacchino'
    return function j() {
        console.log('Printing the value of x, from within function j: ', x)
    }
} 

const k = i()
setTimeout(k, 500) // invoke k (which is j) after 500ms

In einer Schließung werden die Variablen in der äußeren lexikalischen Umgebung selbst sind verfügbar, no Kopien.

function l() {
  var y = 'vanilla';

  return {
    setY: function(value) {
      y = value;
    },
    logY: function(value) {
      console.log('The value of y is: ', y);
    }
  }
}

const o = l()
o.logY() // The value of y is: vanilla
o.setY('chocolate')
o.logY() // The value of y is: chocolate

Die Kette der lexikalischen Umgebungen, die zwischen den Ausführungskontexten über äußere Umgebungsreferenzen verbunden sind, bildet eine Umfangskette und definiert die Bezeichner, die von einer bestimmten Funktion aus sichtbar sind.

Bitte beachten Sie, dass diese Antwort in dem Bemühen um Klarheit und Genauigkeit gegenüber dem Original erheblich geändert wurde.

408voto

Max Tkachenko Punkte 504

OK, 6-jähriger Fan von Schließungen. Willst du das einfachste Beispiel für einen Abschluss hören?

Stellen wir uns die folgende Situation vor: Ein Fahrer sitzt in einem Auto. Das Auto befindet sich in einem Flugzeug. Das Flugzeug befindet sich auf dem Flughafen. Die Möglichkeit des Fahrers, auf Dinge außerhalb seines Autos, aber innerhalb des Flugzeugs zuzugreifen, selbst wenn das Flugzeug den Flughafen verlässt, ist eine Schließung. Das war's. Wenn Sie 27 werden, schauen Sie sich die genauere Erklärung oder das unten stehende Beispiel.

So kann ich meine Flugzeuggeschichte in den Code umsetzen.

var plane = function(defaultAirport) {

  var lastAirportLeft = defaultAirport;

  var car = {
    driver: {
      startAccessPlaneInfo: function() {
        setInterval(function() {
          console.log("Last airport was " + lastAirportLeft);
        }, 2000);
      }
    }
  };
  car.driver.startAccessPlaneInfo();

  return {
    leaveTheAirport: function(airPortName) {
      lastAirportLeft = airPortName;
    }
  }
}("Boryspil International Airport");

plane.leaveTheAirport("John F. Kennedy");

385voto

dlaliberte Punkte 3182

Dies ist ein Versuch, einige (mögliche) Missverständnisse über Verschlüsse auszuräumen, die in einigen der anderen Antworten auftauchen.

  • Ein Abschluss wird nicht nur erstellt, wenn Sie eine innere Funktion zurückgeben. In der Tat, die einschließende Funktion muss überhaupt nicht zurückkehren damit sein Abschluss erstellt werden kann. Sie könnten stattdessen Ihre innere Funktion einer Variablen in einem äußeren Bereich zuweisen oder sie als Argument an eine andere Funktion übergeben, wo sie sofort oder zu einem späteren Zeitpunkt aufgerufen werden könnte. Daher wird der Abschluss der umschließenden Funktion wahrscheinlich erstellt sobald die einschließende Funktion aufgerufen wird da jede innere Funktion Zugriff auf diese Schließung hat, wenn die innere Funktion aufgerufen wird, bevor oder nachdem die umschließende Funktion zurückkehrt.
  • Ein Abschluss verweist nicht auf eine Kopie der alte Werte von Variablen in seinem Geltungsbereich. Die Variablen selbst sind Teil des Abschlusses, so dass der Wert, der beim Zugriff auf eine dieser Variablen angezeigt wird, der neueste Wert zum Zeitpunkt des Zugriffs ist. Dies ist der Grund, warum innere Funktionen, die innerhalb von Schleifen erstellt werden, problematisch sein können, da jede Funktion auf dieselben äußeren Variablen zugreift, anstatt eine Kopie der Variablen zum Zeitpunkt der Erstellung oder des Aufrufs der Funktion zu erhalten.
  • Zu den "Variablen" in einem Abschluss gehören alle benannten Funktionen innerhalb der Funktion deklariert. Sie enthalten auch Argumente der Funktion. Eine Closure hat auch Zugriff auf die Variablen der Closure, die sie enthält, und zwar bis hin zum globalen Bereich.
  • Verschlüsse verbrauchen Speicher, aber sie verursachen keine Speicherlecks da JavaScript seine eigenen zirkulären Strukturen, auf die nicht verwiesen wird, selbst aufräumt. Speicherlecks im Internet Explorer, die mit Closures zu tun haben, entstehen, wenn DOM-Attributwerte, die auf Closures verweisen, nicht getrennt werden und somit Verweise auf möglicherweise zirkuläre Strukturen beibehalten werden.

255voto

Nathan Long Punkte 117688

Ich habe vor einiger Zeit einen Blog-Beitrag geschrieben, in dem ich die Verschlüsse erklärt habe. Hier ist, was ich über Verschlüsse in Bezug auf die folgenden Punkte gesagt habe por qué würden Sie einen wollen.

Closures sind eine Möglichkeit, eine Funktion haben. persistente, private Variablen - das heißt, Variablen, die nur eine Funktion kennt, bei der sie Informationen aus früheren Zeiten die sie ausgeführt wurde.

In diesem Sinne lassen sie eine Funktion ein wenig wie ein Objekt mit privaten Attributen handeln.

Vollständiger Beitrag:

Was sind diese Verschlüsse?

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X