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.

6voto

nomen Punkte 3526

Ich denke, es ist sinnvoll, einen Schritt zurückzutreten und einen allgemeineren Begriff einer "Schließung" zu untersuchen - den so genannten "Verknüpfungsoperator".

In der Mathematik ist ein "join"-Operator eine Funktion auf einer teilweise geordneten Menge, die das kleinste Objekt zurückgibt, das größer oder gleich seinen Argumenten ist. In Symbolen ist join [a,b] = d so, dass d >= a und d >= b ist, es aber kein e gibt, so dass d > e >= a oder d > e >= b ist.

Durch die Verbindung erhält man also das kleinste Ding, das "größer" ist als die Teile.

Beachten Sie nun, dass JavaScript-Bereiche eine teilweise geordnete Struktur sind. Es gibt also einen sinnvollen Begriff für einen Join. Insbesondere ist ein Join von Scopes der kleinste Scope, der größer ist als die ursprünglichen Scopes. Dieser Bereich wird als Verschluss .

Eine Closure für die Variablen a, b, c ist also der kleinste Scope (im Gitter der Scopes für Ihr Programm!), der a, b und c in den Scope bringt.

6voto

williambq Punkte 1085

Ich habe sie alle schon einmal gelesen, und sie sind alle sehr informativ. Einige kommen der einfachen Erklärung sehr nahe und werden dann komplex oder bleiben abstrakt, was den Zweck verfehlt und eine sehr einfache Anwendung in der realen Welt nicht aufzeigt.

Obwohl man beim Durchkämmen der Beispiele und Erklärungen durch Kommentare und Code eine gute Vorstellung davon bekommt, was Closures sind und was nicht, war ich immer noch unzufrieden mit einer sehr einfachen Illustration, die mir half, den Nutzen von Closures zu verstehen, ohne so komplex zu werden. Meine Frau möchte Programmieren lernen, und ich dachte mir, dass ich in der Lage sein müsste, ihr nicht nur das Was, sondern auch das Warum und das Wie zu zeigen.

Ich bin mir nicht sicher, ob ein Sechsjähriger dies verstehen wird, aber ich denke, dass es einen einfachen Fall in der realen Welt etwas besser veranschaulicht, der tatsächlich nützlich sein könnte und leicht verständlich ist.

Eines der besten (oder am ehesten einfachsten) ist die Nacherzählung des Beispiels von Morris' Closures for Dummies.

Wenn man das "SayHi2Bob"-Konzept noch einen Schritt weiterdenkt, werden die beiden grundlegenden Dinge deutlich, die man beim Lesen aller Antworten herausfinden kann:

  1. Closures haben Zugriff auf die Variablen der enthaltenen Funktion.
  2. Closures bleiben in ihrem eigenen Speicherbereich bestehen (und sind daher für alle Arten von Oop-y-Instanziierung nützlich)

Um mir das zu beweisen und zu demonstrieren, habe ich eine kleine Fiedel gebaut:

http://jsfiddle.net/9ZMyr/2/

function sayHello(name) {
  var text = 'Hello ' + name; // Local variable
  console.log(text);
  var sayAlert = function () {
      alert(text);
  }
  return sayAlert;
}

sayHello(); 
/* This will write 'Hello undefined' to the console (in Chrome anyway), 
but will not alert though since it returns a function handle to nothing). 
Since no handle or reference is created, I imagine a good js engine would 
destroy/dispose of the internal sayAlert function once it completes. */

// Create a handle/reference/instance of sayHello() using the name 'Bob'
sayHelloBob = sayHello('Bob');
sayHelloBob();

// Create another handle or reference to sayHello with a different name
sayHelloGerry = sayHello('Gerry');
sayHelloGerry();

/* Now calling them again demonstrates that each handle or reference contains its own 
unique local variable memory space. They remain in memory 'forever' 
(or until your computer/browser explode) */
sayHelloBob();
sayHelloGerry();

Dies veranschaulicht die beiden grundlegenden Konzepte, die Sie über Verschlüsse verstehen sollten.

Einfach ausgedrückt, um zu erklären, warum dies nützlich ist, habe ich eine Basisfunktion, auf die ich Verweise oder Handles erstellen kann, die eindeutige Daten enthalten, die innerhalb dieses Speicherverweises bestehen bleiben. Ich muss die Funktion nicht jedes Mal neu schreiben, wenn ich den Namen einer Person sagen möchte. Ich habe diese Routine gekapselt und sie wiederverwendbar gemacht.

Für mich führt dies zumindest zu den grundlegenden Konzepten von Konstruktoren, Oop-Praktiken, Singletons vs. instanziierte Instanzen mit ihren eigenen Daten usw. usw.

Wenn Sie einen Neuling damit beginnen, können Sie zu komplexeren Aufrufen auf der Basis von Objekteigenschaften/Mitgliedern übergehen, und hoffentlich werden die Konzepte übernommen.

4voto

Mike Robinson Punkte 7892

Außerdem... Vielleicht sollten wir Ihren 27-jährigen Freund ein wenig unterstützen. schlaff, weil das gesamte Konzept der "Verschlüsse" wirklich ist(!) ... Voodoo!

Ich meine damit: (a) Sie erwarten es intuitiv nicht ...UND... (b) wenn sich jemand die Zeit nimmt, es Ihnen zu erklären, erwarten Sie sicher nicht, dass es arbeiten!

Die Intuition sagt Ihnen: "Das muss Unsinn sein... sicher Das muss zu einem Syntaxfehler führen oder so!" Wie um alles in der Welt(!) könnte man tatsächlich "eine Funktion aus der Mitte von wo auch immer" ziehen, so dass man [noch!] tatsächlich Lese-/Schreibzugriff auf den Kontext von "wo auch immer" hat war -at?!"

Wenn Sie endlich erkennen, dass so etwas möglich ist möglich, dann ... sicher ... jedermanns im Nachhinein wäre die Reaktion: "whoa-a-a-a-a(!)... kew-el-l-l-l...(!!!)"

Doch zunächst gilt es, eine "große kontraintuitive Hürde" zu überwinden. Die Intuition gibt Ihnen eine Menge völlig plausibler Erwartungen, dass eine solche Sache "von Kurs, absolut unsinnig und daher völlig unmöglich."

Wie ich schon sagte: "Es ist Voodoo."

4voto

zak.http Punkte 306

Ein Closure ist einfach, wenn eine Funktion Zugriff auf ihren äußeren Bereich hat, auch nachdem die Funktion des Bereichs die Ausführung beendet hat. Beispiel:

function multiplier(n) {
    function multiply(x) {
          return n*x;
    }
    return mutliply;
}

var 10xmultiplier = multiplier(10);
var x = 10xmultiplier(5); // x= 50

können wir sehen, dass die innere Funktion multiply auch nach der Ausführung des Multiplikators noch Zugriff auf den Wert von x hat, der in diesem Beispiel 10 ist.

Eine sehr häufige Verwendung von Closures ist das Currying (das gleiche Beispiel wie oben), bei dem wir unsere Funktion nach und nach mit Parametern würzen, anstatt alle Argumente auf einmal zu liefern.

Wir können dies erreichen, weil Javascript (zusätzlich zur prototypischen OOP) erlaubt, in einer funktionalen Art und Weise zu programmieren, in der Funktionen höherer Ordnung andere Funktionen als Argumente annehmen können (Fisrt Class Functions). funktionale programmierung in wikipedia

Ich empfehle Ihnen dringend, dieses Buch von Kyle Simpson zu lesen: 2 Ein Teil der Buchreihe ist den Verschlüssen gewidmet und heißt Scope und Verschlüsse. you don't know js: kostenlose Lektüre auf github

2voto

Gerard ONeill Punkte 3528

Eine Schließung ist eine Funktion, die Zugriff auf Informationen aus der Umgebung hat, in der sie definiert wurde.

Für einige sind die Informationen die Wert in der Umwelt zum Zeitpunkt der Schöpfung. Für andere sind die Informationen die Variablen in der Umgebung zum Zeitpunkt der Erstellung.

Wenn die lexikalische Umgebung, auf die sich die Schließung bezieht, zu einer Funktion gehört, die beendet wurde, dann (im Falle einer Schließung, die sich auf die Variablen in der Umgebung bezieht) werden diese lexikalischen Variablen weiterhin existieren, um von der Schließung referenziert zu werden.

Eine Closure kann als Spezialfall von globalen Variablen betrachtet werden - mit einer privaten Kopie, die nur für die Funktion erstellt wird.

Man kann es sich auch als eine Methode vorstellen, bei der die Umgebung eine bestimmte Instanz eines Objekts ist, dessen Eigenschaften die Variablen in der Umgebung sind.

Ersteres (Schließung als Umgebung) ähnelt letzterem, wobei die Umgebungskopie eine Kontextvariable ist, die in ersterem an jede Funktion übergeben wird, und in letzterem die Instanzvariablen eine Kontextvariable bilden.

Eine Closure ist also eine Möglichkeit, eine Funktion aufzurufen, ohne den Kontext explizit als Parameter oder als Objekt in einem Methodenaufruf angeben zu müssen.

var closure = createclosure(varForClosure);
closure(param1);  // closure has access to whatever createclosure gave it access to,
                  // including the parameter storing varForClosure.

gegen

var contextvar = varForClosure; // use a struct for storing more than one..
contextclosure(contextvar, param1);

gegen

var contextobj = new contextclass(varForClosure);
contextobj->objclosure(param1);

Für wartbaren Code empfehle ich den objektorientierten Weg. Für eine schnelle und einfache Reihe von Aufgaben (z. B. das Erstellen eines Rückrufs) kann eine Schließung jedoch natürlicher und klarer werden, insbesondere im Kontext von Lamda- oder anonymen Funktionen.

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