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.

89voto

Gerardo Lima Punkte 5995

Ich weiß, dass es bereits viele Lösungen gibt, aber ich denke, dass dieses kleine und einfache Skript nützlich sein kann, um das Konzept zu demonstrieren:

// makeSequencer will return a "sequencer" function
var makeSequencer = function() {
    var _count = 0; // not accessible outside this function
    var sequencer = function () {
        return _count++;
    }
    return sequencer;
}

var fnext = makeSequencer();
var v0 = fnext();     // v0 = 0;
var v1 = fnext();     // v1 = 1;
var vz = fnext._count // vz = undefined

86voto

Saber Punkte 4515

Der Autor von Schließungen hat Schließungen ziemlich gut erklärt, den Grund, warum wir sie brauchen, und auch die LexicalEnvironment erklärt, die für das Verständnis von Schließungen notwendig ist.
Hier ist die Zusammenfassung:

Was ist, wenn auf eine Variable zugegriffen wird, die aber nicht lokal ist? Wie hier:

Enter image description here

In diesem Fall findet der Interpreter die Variable in der Datei äußeren LexicalEnvironment Objekt.

Das Verfahren besteht aus zwei Schritten:

  1. Erstens wird eine Funktion f nicht in einem leeren Raum erstellt, sondern Raum erstellt. Es gibt ein aktuelles LexicalEnvironment-Objekt. In dem Fall oben ist es window (a ist zum Zeitpunkt der Funktionserstellung undefiniert Erstellung).

Enter image description here

Wenn eine Funktion erstellt wird, erhält sie eine verborgene Eigenschaft namens [[Scope]], die auf die aktuelle LexicalEnvironment verweist.

Enter image description here

Wenn eine Variable gelesen wird, aber nirgendwo gefunden werden kann, wird ein Fehler erzeugt.

Verschachtelte Funktionen

Funktionen können ineinander verschachtelt werden und bilden eine Kette von LexicalEnvironments, die auch als Scope-Kette bezeichnet werden kann.

Enter image description here

Die Funktion g hat also Zugriff auf g, a und f.

Schließungen

Eine verschachtelte Funktion kann weiterlaufen, nachdem die äußere Funktion beendet wurde:

Enter image description here

Markierung von LexicalEnvironments:

Enter image description here

Wie wir sehen, this.say ist eine Eigenschaft des Benutzerobjekts und bleibt daher auch nach Beendigung von User bestehen.

Und wenn Sie sich erinnern, als this.say erstellt wird, erhält sie (wie jede Funktion) eine interne Referenz this.say.[[Scope]] auf die aktuelle LexicalEnvironment. Die LexicalEnvironment der aktuellen User-Ausführung bleibt also im Speicher. Alle Variablen von User sind auch seine Eigenschaften, also werden sie auch sorgfältig aufbewahrt und nicht wie üblich weggeworfen.

Damit soll sichergestellt werden, dass die innere Funktion auf eine äußere Variable zugreifen kann, wenn sie dies in der Zukunft tun möchte.

Zusammengefasst:

  1. Die innere Funktion behält einen Verweis auf die äußere LexicalEnvironment.
  2. Die innere Funktion kann auf Variablen aus ihr zugreifen jederzeit zugreifen, auch wenn die äußere Funktion beendet ist.
  3. Der Browser behält die LexicalEnvironment und alle ihre Eigenschaften (Variablen) im Speicher, bis eine innere Funktion auf sie verweist.

Dies nennt man einen Abschluss.

85voto

StewShack Punkte 139

Du veranstaltest eine Pyjamaparty und lädst Dan ein. Du sagst Dan, er soll einen XBox-Controller mitbringen.

Dan lädt Paul ein. Dan bittet Paul, einen Controller mitzubringen. Wie viele Controller wurden zu der Party mitgebracht?

function sleepOver(howManyControllersToBring) {

    var numberOfDansControllers = howManyControllersToBring;

    return function danInvitedPaul(numberOfPaulsControllers) {
        var totalControllers = numberOfDansControllers + numberOfPaulsControllers;
        return totalControllers;
    }
}

var howManyControllersToBring = 1;

var inviteDan = sleepOver(howManyControllersToBring);

// The only reason Paul was invited is because Dan was invited. 
// So we set Paul's invitation = Dan's invitation.

var danInvitedPaul = inviteDan(howManyControllersToBring);

alert("There were " + danInvitedPaul + " controllers brought to the party.");

79voto

John Pick Punkte 5447

JavaScript-Funktionen können auf ihre:

  1. Argumente
  2. Lokale (d.h. ihre lokalen Variablen und lokalen Funktionen)
  3. Umwelt, die Folgendes umfasst:
    • Globals, einschließlich des DOM
    • alles in äußeren Funktionen

Wenn eine Funktion auf ihre Umgebung zugreift, dann ist die Funktion eine Schließung.

Beachten Sie, dass äußere Funktionen nicht erforderlich sind, obwohl sie Vorteile bieten, auf die ich hier nicht eingehe. Indem sie auf Daten in ihrer Umgebung zugreift, hält eine Closure diese Daten am Leben. Im Unterfall der äußeren/inneren Funktionen kann eine äußere Funktion lokale Daten erstellen und schließlich beenden, und dennoch, wenn eine oder mehrere innere Funktionen nach dem Beenden der äußeren Funktion überleben, dann halten die inneren Funktionen die lokalen Daten der äußeren Funktion am Leben.

Beispiel für einen Abschluss, der die globale Umgebung verwendet:

Stellen Sie sich vor, dass die Stack Overflow-Schaltflächenereignisse Vote-Up und Vote-Down als Closures, voteUp_click und voteDown_click, implementiert sind, die Zugriff auf externe Variablen isVotedUp und isVotedDown haben, die global definiert sind. (Der Einfachheit halber beziehe ich mich auf die Frage-Abstimmungs-Schaltflächen von StackOverflow, nicht auf das Array der Antwort-Abstimmungs-Schaltflächen).

Wenn der Benutzer auf die Schaltfläche VoteUp klickt, prüft die Funktion voteUp_click, ob isVotedDown == true ist, um festzustellen, ob die Stimme nach oben abgegeben werden soll oder ob lediglich eine Abstimmung nach unten abgebrochen werden soll. Die Funktion voteUp_click ist eine Schließung, da sie auf ihre Umgebung zugreift.

var isVotedUp = false;
var isVotedDown = false;

function voteUp_click() {
  if (isVotedUp)
    return;
  else if (isVotedDown)
    SetDownVote(false);
  else
    SetUpVote(true);
}

function voteDown_click() {
  if (isVotedDown)
    return;
  else if (isVotedUp)
    SetUpVote(false);
  else
    SetDownVote(true);
}

function SetUpVote(status) {
  isVotedUp = status;
  // Do some CSS stuff to Vote-Up button
}

function SetDownVote(status) {
  isVotedDown = status;
  // Do some CSS stuff to Vote-Down button
}

Alle vier Funktionen sind Abschlüsse, da sie alle auf ihre Umgebung zugreifen.

60voto

grateful Punkte 1098

Als Vater eines 6-Jährigen, der derzeit kleine Kinder unterrichtet (und ein relativer Neuling im Programmieren ohne formale Ausbildung, so dass Korrekturen erforderlich sein werden), denke ich, dass die Lektion am besten durch praktisches Spielen vermittelt werden kann. Wenn der 6-Jährige bereit ist zu verstehen, was ein Verschluss ist, dann ist er alt genug, um es selbst zu versuchen. Ich würde vorschlagen, den Code in jsfiddle.net einzufügen, ein wenig zu erklären und sie dann allein zu lassen, damit sie ein einzigartiges Lied zusammenstellen können. Der erklärende Text unten ist wahrscheinlich eher für einen 10-Jährigen geeignet.

function sing(person) {

    var firstPart = "There was " + person + " who swallowed ";

    var fly = function() {
        var creature = "a fly";
        var result = "Perhaps she'll die";
        alert(firstPart + creature + "\n" + result);
    };

    var spider = function() {
        var creature = "a spider";
        var result = "that wiggled and jiggled and tickled inside her";
        alert(firstPart + creature + "\n" + result);
    };

    var bird = function() {
        var creature = "a bird";
        var result = "How absurd!";
        alert(firstPart + creature + "\n" + result);
    };

    var cat = function() {
        var creature = "a cat";
        var result = "Imagine That!";
        alert(firstPart + creature + "\n" + result);
    };

    fly();
    spider();
    bird();
    cat();
}

var person="an old lady";

sing(person);

ANLEITUNGEN

DATEN: Daten sind eine Sammlung von Fakten. Das können Zahlen, Wörter, Messungen, Beobachtungen oder auch nur Beschreibungen von Dingen sein. Man kann sie nicht anfassen, riechen oder schmecken. Man kann sie aufschreiben, sprechen und hören. Sie können sie verwenden, um erstellen. berühren, riechen und schmecken mit Hilfe eines Computers. Ein Computer kann sie mit Hilfe von Code nutzbar machen.

CODE: Alle oben genannten Texte werden als Code . Es ist in JavaScript geschrieben.

JAVASCRIPT: JavaScript ist eine Sprache. So wie Englisch, Französisch oder Chinesisch Sprachen sind. Es gibt viele Sprachen, die von Computern und anderen elektronischen Prozessoren verstanden werden. Damit JavaScript von einem Computer verstanden wird, braucht es einen Interpreter. Stellen Sie sich vor, ein Lehrer, der nur Russisch spricht, unterrichtet Ihre Klasse in der Schule. Wenn der Lehrer " " sagt, würde die Klasse es nicht verstehen. Aber zum Glück haben Sie einen russischen Schüler in Ihrer Klasse, der allen sagt, dass dies "Setzt euch alle hin" bedeutet - also tun sie es alle. Die Klasse ist wie ein Computer und der russische Schüler ist der Dolmetscher. Der gebräuchlichste Interpreter für JavaScript ist ein Browser.

BROWSER: Wenn Sie auf einem Computer, Tablet oder Telefon eine Verbindung zum Internet herstellen, um eine Website zu besuchen, verwenden Sie einen Browser. Beispiele, die Sie vielleicht kennen, sind Internet Explorer, Chrome, Firefox und Safari. Der Browser kann JavaScript verstehen und dem Computer sagen, was er tun soll. Die JavaScript-Anweisungen werden als Funktionen bezeichnet.

FUNKTION: Eine Funktion in JavaScript ist wie eine Fabrik. Sie kann eine kleine Fabrik mit nur einer Maschine darin sein. Oder sie kann viele andere kleine Fabriken enthalten, jede mit vielen Maschinen, die verschiedene Aufgaben erledigen. In einer echten Bekleidungsfabrik könnten Stoffbahnen und Garnspulen hineingehen und T-Shirts und Jeans herauskommen. Unsere JavaScript-Fabrik verarbeitet nur Daten, sie kann nicht nähen, ein Loch bohren oder Metall schmelzen. In unserer JavaScript-Fabrik gehen Daten rein und Daten kommen raus.

Dieser ganze Datenkram hört sich etwas langweilig an, aber er ist wirklich sehr cool. Wir könnten eine Funktion haben, die einem Roboter sagt, was er zum Abendessen machen soll. Nehmen wir an, ich lade dich und deinen Freund zu mir nach Hause ein. Du magst am liebsten Hühnerbeine, ich mag Würstchen, dein Freund will immer das, was du willst, und mein Freund isst kein Fleisch.

Ich habe keine Zeit, einkaufen zu gehen, also muss die Funktion wissen, was wir im Kühlschrank haben, um Entscheidungen zu treffen. Jede Zutat hat eine andere Garzeit, und wir wollen, dass der Roboter alles zur gleichen Zeit heiß serviert. Wir müssen die Funktion mit den Daten darüber versorgen, was wir mögen, die Funktion könnte mit dem Kühlschrank "sprechen" und die Funktion könnte den Roboter steuern.

Eine Funktion besteht normalerweise aus einem Namen, Klammern und geschweiften Klammern. Zum Beispiel so:

function cookMeal() {  /*  STUFF INSIDE THE FUNCTION  */  }

なお /*...*/ y // verhindern, dass der Code vom Browser gelesen wird.

NAME: Sie können eine Funktion so nennen, wie Sie wollen. Das Beispiel "cookMeal" ist typisch, da es zwei Wörter zusammenfügt und dem zweiten einen Großbuchstaben vorangestellt hat - aber das ist nicht notwendig. Es darf weder ein Leerzeichen enthalten noch eine Zahl sein.

PARENTHESEN: "Klammern" oder () sind der Briefkasten an der Tür der JavaScript-Funktionsfabrik oder ein Briefkasten an der Straße, über den Informationspakete an die Fabrik geschickt werden. Manchmal ist der Briefkasten auch mit zum Beispiel cookMeal(you, me, yourFriend, myFriend, fridge, dinnerTime) In diesem Fall wissen Sie, welche Daten Sie ihm geben müssen.

BRACES: "Klammern", die wie folgt aussehen {} sind die getönten Fenster unserer Fabrik. Von der Fabrik aus kann man hinaussehen, aber von außen kann man nicht hineinsehen.

DAS OBIGE LANGE CODEBEISPIEL

Unser Code beginnt mit dem Wort Funktion damit wir wissen, dass es eine ist! Dann wird der Name der Funktion singen - das ist meine eigene Beschreibung, worum es bei der Funktion geht. Dann Klammern () . Die Klammern sind immer für eine Funktion da. Manchmal sind sie leer, und manchmal enthalten sie etwas. In dieser Klammer steht ein Wort: (person) . Danach gibt es eine Klammer wie diese { . Dies markiert den Beginn der Funktion sing() . Sie hat einen Partner, der das Ende der sing() wie diese }

function sing(person) {  /* STUFF INSIDE THE FUNCTION */  }

Diese Funktion könnte also etwas mit Gesang zu tun haben und einige Daten über eine Person benötigen. Sie enthält Anweisungen, was mit diesen Daten geschehen soll.

Nun, nach der Funktion sing() Am Ende des Codes befindet sich die Zeile

var person="an old lady";

VARIABLE: Die Buchstaben var steht für "variabel". Eine Variable ist wie ein Briefumschlag. Auf der Außenseite ist dieser Umschlag mit "Person" beschriftet. Innen enthält er einen Zettel mit den Informationen, die unsere Funktion benötigt, einige Buchstaben und Leerzeichen, die wie ein Stück Schnur aneinandergereiht sind (man nennt sie Schnur) und einen Satz ergeben, der "eine alte Dame" lautet. Unser Umschlag könnte auch andere Dinge enthalten, wie Zahlen (Integer genannt), Anweisungen (Funktionen genannt), Listen (genannt Arrays ). Da diese Variable außerhalb aller geschweiften Klammern geschrieben wird {} und da Sie durch die getönten Fenster sehen können, wenn Sie sich innerhalb der geschweiften Klammern befinden, kann diese Variable von überall im Code gesehen werden. Wir nennen dies eine "globale Variable".

GLOBALE VARIABLE: Person ist eine globale Variable, d. h., wenn Sie ihren Wert von "eine alte Dame" in "ein junger Mann" ändern, wird die Person bleibt ein junger Mann, bis du dich entscheidest, es wieder zu ändern und jede andere Funktion im Code sehen kann, dass es ein junger Mann ist. Drücken Sie die F12 oder schauen Sie in den Optionseinstellungen nach, um die Entwicklerkonsole eines Browsers zu öffnen und geben Sie "person" ein, um zu sehen, wie hoch dieser Wert ist. Geben Sie ein. person="a young man" um ihn zu ändern, und geben Sie dann erneut "Person" ein, um zu sehen, dass er sich geändert hat.

Danach folgt die Zeile

sing(person);

Diese Zeile ruft die Funktion auf, als ob sie einen Hund rufen würde

"Komm schon singen , Komm und hol dir Person !"

Wenn der Browser den JavaScript-Code geladen und diese Zeile erreicht hat, startet er die Funktion. Ich habe die Zeile an das Ende gesetzt, um sicherzustellen, dass der Browser alle Informationen hat, die er zum Ausführen der Funktion benötigt.

Funktionen definieren Aktionen - die Hauptfunktion ist das Singen. Sie enthält eine Variable namens ersterTeil die für den Gesang über die Person gilt, die für jede der Strophen des Liedes gilt: "Es war " Person + " der verschluckte". Wenn Sie eingeben ersterTeil in die Konsole eingeben, erhalten Sie keine Antwort, da die Variable in einer Funktion eingeschlossen ist - der Browser kann nicht in das getönte Fenster der geschweiften Klammern sehen.

ABSCHLÜSSE: Die Abschlüsse sind die kleineren Funktionen, die sich innerhalb der großen sing() Funktion. Die kleinen Fabriken innerhalb der großen Fabrik. Sie haben jeweils ihre eigenen geschweiften Klammern, was bedeutet, dass die Variablen in ihnen von außen nicht zu sehen sind. Aus diesem Grund sind die Namen der Variablen ( Lebewesen y Ergebnis ) können in den Abschlüssen wiederholt werden, jedoch mit unterschiedlichen Werten. Wenn Sie diese Variablennamen in das Konsolenfenster eingeben, erhalten Sie den Wert nicht, da er von zwei Schichten getönter Fenster verdeckt wird.

Die Verschlüsse wissen alle, was die sing() Die Variable der Funktion namens ersterTeil ist, weil sie durch ihre getönten Fenster hinaussehen können.

Nach den Schließungen kommen die Linien

fly();
spider();
bird();
cat();

Die Funktion sing() ruft jede dieser Funktionen in der angegebenen Reihenfolge auf. Dann ist die Arbeit der sing()-Funktion getan.

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