Frage

Wie würden Sie Javascript Schließungen jemand mit dem Wissen über die Konzepte, die sie bestehen aus (zum Beispiel Funktionen, Variablen und dergleichen) erklären, aber nicht versteht, Verschlüsse selbst?

Ich habe das Schema Beispiel auf Wikipedia gegeben , aber leider ist es tut hilft nicht.

War es hilfreich?

Lösung

JavaScript-Verschlüsse für Anfänger

übermittelt von Morris am Di, 2006-02-21 10.19. Community bearbeitet seit.

Verschlüsse sind keine Magie

Diese Seite erklärt, Verschlüsse, so dass ein Programmierer sie verstehen kann - Arbeits JavaScript-Code. Es ist nicht für Gurus oder funktionelle Programmierer.

Verschlüsse sind nicht schwer zu verstehen, sobald das Kernkonzept grokked ist. Allerdings sind sie nicht zu verstehen, durch irgendwelche theoretischen oder akademisch orientierte Erklärungen beim Lesen!

Dieser Artikel ist für Programmierer mit etwas Programmiererfahrung in einer Mainstream-Sprache bestimmt ist, und die die folgende JavaScript-Funktion lesen kann:

function sayHello(name) {
  var text = 'Hello ' + name;
  var say = function() { console.log(text); }
  say();
}
sayHello('Joe');

Zwei kurze Zusammenfassungen

  • Wenn eine Funktion (foo) andere Funktionen erklärt (bar und baz), schuf die Familie von lokalen Variablen in foo ist nicht zerstört , wenn die Funktion beendet. Die Variablen nur unsichtbar für die Außenwelt. foo kann daher listig die Funktionen bar und baz zurückzukehren, und sie können weiterhin miteinander durch diese abgesperrten Familie von Variablen (nachstehend „closure“) lesen, schreiben und kommunizieren, dass niemand sonst mit einmischen kann, nicht einmal jemand, ruft foo wieder in der Zukunft.

  • Ein Verschluß ist eine Möglichkeit der Unterstützung erstklassige Funktionen ; es ist ein Ausdruck, der Variablen innerhalb ihres Anwendungsbereichs referenzieren kann (wenn es wurde zuerst erklärt), einer Variablen zugewiesen werden, als ein Argument an eine Funktion übergeben werden, oder als ein Funktionsergebnis zurückgegeben werden.

Ein Beispiel für eine Schließung

Der folgende Code gibt einen Verweis auf eine Funktion:

function sayHello2(name) {
  var text = 'Hello ' + name; // Local variable
  var say = function() { console.log(text); }
  return say;
}
var say2 = sayHello2('Bob');
say2(); // logs "Hello Bob"

Die meisten JavaScript-Programmierer werden verstehen, wie ein Verweis auf eine Funktion einer Variablen (say2) in dem obigen Code zurückgegeben wird. Wenn Sie dies nicht tun, dann müssen Sie auf das schauen, bevor Sie Schließungen lernen können. Ein Programmierer C unter Verwendung würde denken, der Funktion als einen Zeiger auf eine Funktion zurückkehrt, und dass die Variablen say und say2 wurden jeweils ein Zeiger auf eine Funktion.

Es gibt einen entscheidenden Unterschied zwischen einem C-Zeiger auf eine Funktion und einen JavaScript-Verweise auf eine Funktion. In JavaScript können Sie eine Funktion Bezugsgröße denken, da beide einen Zeiger auf eine Funktion, die und als versteckten Zeiger auf eine Schließung.

Der obige Code hat einen Verschluss, da die anonyme Funktion function() { console.log(text); } deklariert innen eine weitere Funktion, sayHello2() in diesem Beispiel. In JavaScript, wenn Sie das function Schlüsselwort in einer anderen Funktion zu verwenden, erstellen Sie eine Schließung.

In C und die meisten anderen gängigen Sprachen, nach eine Funktion zurückgibt, werden alle lokalen Variablen sind nicht mehr zugänglich, weil der Stack-Frame zerstört wird.

In JavaScript, wenn Sie eine Funktion innerhalb einer anderen Funktion deklarieren, dann werden die lokalen Variablen der äußeren Funktion kann nach der Rückkehr aus zugänglich bleiben. Dies wird oben gezeigt, weil wir die Funktion say2() rufen, nachdem wir aus sayHello2() zurückgekehrt. Beachten Sie, dass der Code, den wir Referenzen die Variable text nennen, das war ein lokale Variable der Funktion sayHello2().

function() { console.log(text); } // Output of say2.toString();

am Ausgang des say2.toString() suchen, können wir sehen, dass der Code auf die Variable text bezieht. Die anonyme Funktion kann text wh Referenzich hält den Wert 'Hello Bob' weil die lokalen Variablen von sayHello2() haben in einem Verschluss am Leben im Geheimen gehalten.

Das Genie ist, dass in JavaScript eine Funktionsreferenz auch einen geheimen Bezug auf die Schließung hat es erstellt wurde -. Ähnlich, wie die Delegierten sind ein Methodenzeiger plus ein geheimer Verweis auf ein Objekt

Weitere Beispiele

Aus irgendeinem Grund Schließungen scheinen wirklich schwer zu verstehen, wenn man über sie lesen, aber wenn Sie einige Beispiele sehen, wird klar, wie sie funktionieren (es dauerte eine Weile). Ich empfehle Arbeit durch die Beispiele sorgfältig, bis Sie wissen, wie sie funktionieren. Wenn Sie mit Schließungen beginnen, ohne genau zu wissen, wie sie funktionieren, würden Sie bald einige sehr seltsame Fehler erstellen!

Beispiel 3

Dieses Beispiel zeigt, dass die lokalen Variablen nicht kopiert werden - sie Bezug gehalten werden. Es ist, als ob der Stack-Frame in Erinnerung lebendig bleibt auch nach der äußeren Funktion beendet wird!

function say667() {
  // Local variable that ends up within closure
  var num = 42;
  var say = function() { console.log(num); }
  num++;
  return say;
}
var sayNumber = say667();
sayNumber(); // logs 43

Beispiel 4

Alle drei globalen Funktionen haben einen gemeinsamen Bezug auf das gleiche Verschluss, weil sie alle in einem einzigen Aufruf deklariert werden setupSomeGlobals().

var gLogNumber, gIncreaseNumber, gSetNumber;
function setupSomeGlobals() {
  // Local variable that ends up within closure
  var num = 42;
  // Store some references to functions as global variables
  gLogNumber = function() { console.log(num); }
  gIncreaseNumber = function() { num++; }
  gSetNumber = function(x) { num = x; }
}

setupSomeGlobals();
gIncreaseNumber();
gLogNumber(); // 43
gSetNumber(5);
gLogNumber(); // 5

var oldLog = gLogNumber;

setupSomeGlobals();
gLogNumber(); // 42

oldLog() // 5

Die drei Funktionen haben Zugriff auf die gleichen Schließung geteilt -. Die lokalen Variablen von setupSomeGlobals(), wenn die drei Funktionen definiert wurden

Beachten Sie, dass in dem obigen Beispiel, wenn Sie setupSomeGlobals() wieder anrufen, dann einen neuen Verschluss (Stack-Frame!) Erstellt wird. Die alte gLogNumber, gIncreaseNumber, gSetNumber Variablen werden überschrieben mit neue Funktionen, die den neuen Verschluss haben. (In JavaScript, wenn Sie eine Funktion innerhalb einer anderen Funktion deklarieren, die Innen Funktion (en) ist / neu erstellt werden wieder jeder Zeit die Außen Funktion aufgerufen wird.)

Beispiel 5

Dieses Beispiel zeigt, dass die Schließung alle lokalen Variablen enthält, die innerhalb der äußeren Funktion deklariert wurden, bevor sie verlassen. Beachten Sie, dass die Variable alice tatsächlich nach der anonymen Funktion deklariert wird. Die anonyme Funktion wird erklärt zuerst, und wenn diese Funktion ist es so genannte alice Variable zugreifen können, weil alice im gleichen Umfang ist (JavaScript tut variable Hebe ). Auch sayAlice()() nur direkt ruft die Funktion Referenz von sayAlice() zurück -. Es ist genau das gleiche wie das, was getan wurde bisher aber ohne die temporäre Variable

function sayAlice() {
    var say = function() { console.log(alice); }
    // Local variable that ends up within closure
    var alice = 'Hello Alice';
    return say;
}
sayAlice()();// logs "Hello Alice"

Tricky:. Beachten Sie die say Variable ist innerhalb des Verschlusses auch und konnte durch eine andere Funktion zugegriffen werden, die innerhalb sayAlice() erklärt werden könnte, oder könnte es rekursiv innerhalb der inneren Funktion zugegriffen werden

Beispiel 6

Dies ist ein echter Gotcha für viele Menschen, so müssen Sie es verstehen. Seien Sie sehr vorsichtig, wenn Sie eine Funktion in einer Schleife definieren: die lokalen Variablen aus dem Verschluss kann nicht so tun, als Sie zuerst denken könnte.

Sie müssen die „variable Hebe“ -Funktion in Javascript verstehen, um dieses Beispiel zu verstehen.

function buildList(list) {
    var result = [];
    for (var i = 0; i < list.length; i++) {
        var item = 'item' + i;
        result.push( function() {console.log(item + ' ' + list[i])} );
    }
    return result;
}

function testList() {
    var fnlist = buildList([1,2,3]);
    // Using j only to help prevent confusion -- could use i.
    for (var j = 0; j < fnlist.length; j++) {
        fnlist[j]();
    }
}

 testList() //logs "item2 undefined" 3 times

Die Linie result.push( function() {console.log(item + ' ' + list[i])} fügt einen Verweis auf eine anonyme Funktion dreimal auf das Ergebnis-Array. Wenn Sie nicht so vertraut mit anonymen Funktionen denken Sie daran, wie sind:

pointer = function() {console.log(item + ' ' + list[i])};
result.push(pointer);

Beachten Sie, wenn Sie das Beispiel ausführen, "item2 undefined" dreimal angemeldet ist! Dies liegt daran, wie vorhergehende Beispiele gibt es nur einen Verschluss für die lokalen Variablen für buildList ist (die result, i, list und item). Wenn die anonymen Funktionen sind auf der Linie fnlist[j]() genannt; sie alle verwenden die gleiche einzigen Verschluss, und sie verwenden den aktuellen Wert für i item und innerhalb dieses einen Verschluss (wo i einen Wert von 3 hat, weil die Schleife abgeschlossen war, und einen Wert von item 'item2' hat). Hinweis wir die Indizierung von 0 daher item einen Wert von item2 hat. Und das i ++ wird i auf den Wert 3 erhöhen.

Es kann hilfreich sein, um zu sehen, was passiert, wenn eine Block-Level-Deklaration der Variablen item verwendet wird (über das let Schlüsselwort) anstelle einer funktions scoped Variablendeklaration über das var Schlüsselwort. Wenn die Änderung vorgenommen wird, dann wird jede anonyme Funktion in dem Array result hat einen eigenen Verschluss; wenn das Beispiel ausgeführt wird, ist die Ausgabe wie folgt:

item0 undefined
item1 undefined
item2 undefined

Wenn die Variable i auch anstelle von let mit var definiert ist, dann ist der Ausgang:

item0 1
item1 2
item2 3

Beispiel 7

In diesem letzten Beispiel ist jeder Aufruf die Hauptfunktion erstellt einen separaten Verschluss.

function newClosure(someNum, someRef) {
    // Local variables that end up within closure
    var num = someNum;
    var anArray = [1,2,3];
    var ref = someRef;
    return function(x) {
        num += x;
        anArray.push(num);
        console.log('num: ' + num +
            '; anArray: ' + anArray.toString() +
            '; ref.someVar: ' + ref.someVar + ';');
      }
}
obj = {someVar: 4};
fn1 = newClosure(4, obj);
fn2 = newClosure(5, obj);
fn1(1); // num: 5; anArray: 1,2,3,5; ref.someVar: 4;
fn2(1); // num: 6; anArray: 1,2,3,6; ref.someVar: 4;
obj.someVar++;
fn1(2); // num: 7; anArray: 1,2,3,5,7; ref.someVar: 5;
fn2(2); // num: 8; anArray: 1,2,3,6,8; ref.someVar: 5;

Zusammenfassung

Wenn alles völlig unklar scheint, dann ist das Beste, was zu tun ist, mit den Beispielen zu spielen. eine Erklärung zu lesen, ist viel schwieriger als das Verständnis Beispiele. Meine Erklärungen von Verschlüssen und Stack-Frames usw. sind nicht technisch korrekt - sie sind grobe Vereinfachungen sollten zu verstehen. Sobald die Grundidee grokked ist, können Sie später die Details abholen.

Schlusspunkte:

  • Wenn Sie function in einer anderen Funktion zu verwenden, wird ein Verschluss verwendet.
  • Wenn Sie eval() in einer Funktion verwenden, wird ein Verschluss verwendet. Der Text, den Sie eval können lokale Variablen der Funktion verweisen, und innerhalb eval können Sie sogar neue lokale Variablen erstellen, indem eval('var foo = …') mit
  • Wenn Sie new Function(…) (die Funktion Konstruktor ) innerhalb einer Funktion, es schafft keine Schließung. (Die neue Funktion der lokalen Variablen der äußeren Funktion nicht verweisen können.)
  • Ein Verschluss in JavaScript ist eine Kopie aller lokalen Variablen wie zu halten, so wie sie waren, als eine Funktion verlassen.
  • Es ist wahrscheinlich am besten zu denken, dass ein Verschluss immer nur einen Eintrag auf eine Funktion erstellt wird, und die lokalen Variablen sind in diesem Verschluss hinzugefügt.
  • Ein neuer Satz von lokalen Variablen wird jedes Mal, wenn eine Funktion mit einem Verschluss gehalten wird aufgerufen (vorausgesetzt, dass die Funktion eine Funktionsdeklaration im Innern enthält, und eine Referenz auf diese Innen Funktion wird entweder zurückgeführt oder eine externe Referenz für sie gehalten wird in irgendeiner Art und Weise).
  • Zwei Funktionen könnten schauen, wie sie den gleichen Ausgangstext haben, haben aber völlig anderes Verhalten aufgrund ihrer ‚versteckten‘ Schließung. Ich glaube nicht, JavaScript-Code kann aus tatsächlich finden, wenn eine Funktionsreferenz einen Verschluss hat oder nicht.
  • Wenn Sie dynamische Quellcode Änderungen zu tun versuchen (zB: myFunction = Function(myFunction.toString().replace(/Hello/,'Hola'));), wird es nicht funktionieren, wenn myFunction ein Verschluss (natürlich ist, würden Sie nie zur Laufzeit Quellcode String-Ersetzung zu tun, denken sogar, aber ...).
  • Es ist möglich,Funktionsdeklarationen in Funktionsdeklarationen innerhalb von Funktionen zu erhalten ... und Sie können Verschlüsse auf mehr als eine Ebene zu bekommen.
  • denke ich normalerweise eine Schließung ein Begriff für sowohl die Funktion zusammen mit den Variablen, die erfasst werden. Beachten Sie, dass ich nicht, dass die Definition in diesem Artikel verwenden!
  • Ich vermute, dass Schließungen in JavaScript von jenen unterscheiden, die normalerweise in funktionalen Sprachen gefunden.

Links

Danke

Wenn Sie nur gelernt Verschlüsse (hier oder anderswo!), Dann bin ich Interesse an einem Feedback von Ihnen über alle Änderungen, die Sie könnte darauf hindeuten, dass könnte dieser Artikel klarer. Senden Sie eine E-Mail an morrisjohns.com (morris_closure @). Bitte beachten Sie, dass ich bin kein Guru auf JavaScript -. Noch auf Schließungen


Original-Beitrag von Morris in den Internet Archiven finden .

Andere Tipps

Wenn Sie die Funktion Schlüsselwort innerhalb einer anderen Funktion zu sehen, hat die innere Funktion Zugriff auf Variablen in der äußeren Funktion.

function foo(x) {
  var tmp = 3;

  function bar(y) {
    console.log(x + y + (++tmp)); // will log 16
  }

  bar(10);
}

foo(2);

Das wird immer 16 einzuloggen, weil bar die x zugreifen können, die als Argument definiert wurde foo, und es kann auch tmp von foo zugreifen zu können.

Das ist ein Verschluss. Eine Funktion nicht zu Rückkehr hat , um eine Schließung genannt zu werden. Einfach Variablen außerhalb Ihres unmittelbaren Zugriff auf lexikalischen Gültigkeitsbereich schafft eine Schließung .

function foo(x) {
  var tmp = 3;

  return function (y) {
    console.log(x + y + (++tmp)); // will also log 16
  }
}

var bar = foo(2); // bar is now a closure.
bar(10);

Die obige Funktion wird 16 auch einzuloggen, weil bar noch x und tmp beziehen kann, auch wenn er nicht mehr direkt in dem Rahmen.

Da jedoch tmp noch rumhängen innerhalb bar Schließung wird auch erhöht wird. Es wird jedes Mal, wenn bar rufen erhöht werden.

Das einfachste Beispiel eines Verschlusses ist dies:

var a = 10;

function test() {
  console.log(a); // will output 10
  console.log(b); // will output 6
}
var b = 6;
test();

Wenn eine JavaScript-Funktion aufgerufen wird, wird ein neuer Ausführungskontext erstellt. Zusammen mit den Funktionsargumenten und dem übergeordneten Objekt, auch dieser Ausführungskontext all Variablen empfängt außerhalb davon erklärt (in dem obigen Beispiel sowohl ‚a‘ und ‚b‘).

Es ist möglich, mehr als eine Verschlussfunktion zu erstellen, entweder durch eine Liste von ihnen zurückkehrt oder von ihnen auf globale Variablen zu setzen. Alle diese auf die gleichen x und die gleiche tmp beziehen, sie nicht ihre eigenen Kopien machen.

Hier ist die Zahl x ist eine wörtliche Nummer. Wie bei anderen Literale in JavaScript, wenn foo genannt wird, ist die Zahl x kopiert in foo als Argument x.

Auf der anderen Seite, JavaScript immer Referenzen verwendet, um mit Objekten zu tun. Wenn sagen wir, Sie foo mit einem Objekt aufgerufen, die Schließung kehrt wird Hinweis , dass Original-Objekt!

function foo(x) {
  var tmp = 3;

  return function (y) {
    console.log(x + y + tmp);
    x.memb = x.memb ? x.memb + 1 : 1;
    console.log(x.memb);
  }
}

var age = new Number(2);
var bar = foo(age); // bar is now a closure referencing age.
bar(10);

Wie erwartet, jeder Aufruf bar(10) wird x.memb erhöhen. Was nicht zu erwarten ist, ist, dass x einfach bezieht sich auf das gleiche Objekt wie die age Variable! Nach ein paar Anrufe bar wird age.memb 2 sein! Diese Referenzierung ist die Basis für Speicherlecks mit HTML-Objekten.

Vorwort: diese Antwort geschrieben wurde, als die Frage war:

  

Wie das alte Albert sagte: „Wenn Sie es nicht zu einer sechsjährigen erklären können, Sie wirklich verstehen, es nicht selbst.“ Nun habe ich versucht, JS Schließungen zu einem 27 Jahre alten Freund zu erklären und vollständig. fehlgeschlagen.

     

Kann jemand bedenkt, dass ich bin 6 und seltsam Interesse an diesem Thema?

Ich bin mir ziemlich sicher, dass ich war einer der wenigen Menschen, die die anfängliche Frage wörtlich zu nehmen versucht. Seitdem hat sich die Frage mehrmals mutiert ist, so meine Antwort jetzt unglaublich dumm erscheinen mag und fehl am Platz. Hoffentlich wird die allgemeine Vorstellung von der Geschichte bleibt Spaß für einige.


Ich bin ein großer Fan von Analogie und Metapher, wenn schwierige Begriffe zu erklären, so lassen Sie mich meine Hand mit einer Geschichte versuchen.

Es war einmal:

Es war eine Prinzessin ...

function princess() {

Sie lebte in einer wunderbaren Welt voller Abenteuer. Sie traf ihren Prince Charming, ritten um ihre Welt auf einem Einhorn, kämpfte Drachen begegnet sprechende Tiere und viele andere phantastische Dinge.

    var adventures = [];

    function princeCharming() { /* ... */ }

    var unicorn = { /* ... */ },
        dragons = [ /* ... */ ],
        squirrel = "Hello!";

    /* ... */

Aber sie würde immer wieder auf ihre dumpfen Welt der Aufgaben und Erwachsenen zurückkehren.

    return {

Und sie würde ihr von ihrem neuesten erstaunlichen Abenteuer als Prinzessin oft sagen.

        story: function() {
            return adventures[adventures.length - 1];
        }
    };
}

Aber alles, was sie sehen würden, ist ein kleines Mädchen ...

var littleGirl = princess();

... erzählen Geschichten über Magie und Fantasie.

littleGirl.story();

Und auch wenn die Erwachsenen von echten Prinzessinnen kannte, würden sie nie in den Einhörner oder Drachen glauben, weil sie sie nie sehen konnte. Die Erwachsenen sagten, dass sie nur innerhalb des kleinen Mädchens Phantasie existiert.

Aber wir wissen, die Wahrheit; dass das kleine Mädchen mit der Prinzessin innen ...

... ist wirklich eine Prinzessin mit einem kleinen Mädchen nach innen.

Unter der Frage ernst, sollten wir herausfinden, was ein typischer 6-Jährige ist in der Lage erkennend, zugegebenermaßen aber diejenige, das Interesse an JavaScript ist nicht so typisch.

Entwicklung Kindheit: 5 bis 7 Jahre heißt es:

  

wird Ihr Kind in der Lage sein, zwei-Schritt-Anweisungen zu folgen. Zum Beispiel, wenn Sie mit Ihrem Kind sagen: „in die Küche gehen und mir einen Müllsack“ werden sie in der Lage sein, diese Richtung zu erinnern.

Wir können dieses Beispiel verwenden Schließungen zu erklären, wie folgt:

  

Die Küche ist ein Verschluss, der eine lokale Variable, genannt trashBags hat. Es gibt eine Funktion in der Küche genannt getTrashBag, die einen Müllsack bekommt und gibt es zurück.

Wir können dies in JavaScript-Code wie folgt aus:

function makeKitchen() {
  var trashBags = ['A', 'B', 'C']; // only 3 at first

  return {
    getTrashBag: function() {
      return trashBags.pop();
    }
  };
}

var kitchen = makeKitchen();

console.log(kitchen.getTrashBag()); // returns trash bag C
console.log(kitchen.getTrashBag()); // returns trash bag B
console.log(kitchen.getTrashBag()); // returns trash bag A

Weitere Punkte, die erklären, warum Verschlüsse sind interessant:

  • Jedes Mal, makeKitchen() genannt wird, ein neuer Verschluss mit seinem eigenen separaten trashBags erstellt wird.
  • Die trashBags Variable ist auf die Innenseite jeder Küche lokale und ist außen nicht zugänglich, aber die innere Funktion auf der getTrashBag Eigenschaft hat Zugang zu ihm hat.
  • Jeder Funktionsaufruf erzeugt einen Verschluss, aber es wäre nicht notwendig, den Verschluss zu halten um es sei denn, eine innere Funktion, die den Zugang zum Inneren des Verschlusses hat, kann von außerhalb des Verschlusses aufgerufen werden. Zurückführen des Objekts mit der getTrashBag Funktion tut das hier.

Der Strohmann

Ich muss wissen, wie oft eine Schaltfläche geklickt wurde und etwas zu tun, an jedem dritten Klick ...

ziemlich offensichtlich Lösung

// Declare counter outside event handler's scope
var counter = 0;
var element = document.getElementById('button');

element.addEventListener("click", function() {
  // Increment outside counter
  counter++;

  if (counter === 3) {
    // Do something every third time
    console.log("Third time's the charm!");

    // Reset counter
    counter = 0;
  }
});
<button id="button">Click Me!</button>

Nun wird dies funktionieren, aber es ist in den äußeren Umfang encroach durch eine Variable hinzufügen, deren einziger Zweck es ist, den Überblick über die Zählung zu halten. In manchen Situationen wäre dies bevorzugt als äußere Anwendung Zugriff auf diese Informationen benötigen. Aber in diesem Fall ändern wir nur jedes Verhalten des dritten Klick, so ist es vorzuziehen, umschließen diese Funktionalität innerhalb der Event-Handler .

Betrachten Sie diese Option

var element = document.getElementById('button');

element.addEventListener("click", (function() {
  // init the count to 0
  var count = 0;

  return function(e) { // <- This function becomes the click handler
    count++; //    and will retain access to the above `count`

    if (count === 3) {
      // Do something every third time
      console.log("Third time's the charm!");

      //Reset counter
      count = 0;
    }
  };
})());
<button id="button">Click Me!</button>

Beachten Sie ein paar Dinge hier.

Im obigen Beispiel, ich bin mit dem Schließverhalten von JavaScript. Dieses Verhalten ermöglicht eine beliebige Funktion Zugriff auf den Umfang zu haben, in dem sie erstellt wurde, auf unbestimmte Zeit. Um dies zu praktisch anwenden, rufe ich sofort eine Funktion, die eine andere Funktion zurückgibt, und da die Funktion ich Rückkehr hat Zugriff auf die interne Zählvariable (wegen des Schließverhaltens oben erläutert) führt dies in einem privaten Rahmen für die Nutzung durch die resultierende Funktion ... nicht so einfach? Lassen Sie uns verdünnen Sie es nach unten ...

Eine einfache einzeilige Schließung

//          _______________________Immediately invoked______________________
//         |                                                                |
//         |        Scope retained for use      ___Returned as the____      |
//         |       only by returned function   |    value of func     |     |
//         |             |            |        |                      |     |
//         v             v            v        v                      v     v
var func = (function() { var a = 'val'; return function() { alert(a); }; })();

Alle Variablen außerhalb der zurück Funktion stehen dem zurück Funktion, aber sie sind nicht direkt zur Verfügung, die zurückFunktionsObjekt ...

func();  // Alerts "val"
func.a;  // Undefined

Get it? So in unserem primären Beispiel die Zählvariable wird innerhalb des Verschlusses enthält und immer zur Verfügung, die Event-Handler, so behält er seinen Zustand von Klick zu klicken.

Auch dieser private Variable Zustand ist voll zugänglich, für beiden Lesungen und die Zuordnung zu seinem privaten scoped Variablen.

Dort gehen Sie; Sie können nun vollständig dieses Verhalten eingekapselt wird.

Voll Blog Beitrag (einschließlich jQuery Überlegungen)

Verschlüsse sind schwer zu erklären, weil sie ein bestimmtes Verhalten Arbeit machen werden verwendet, um die jeder intuitiv sowieso arbeiten erwartet. Ich finde, den besten Weg, sie zu erklären (und die Art und Weise, dass I gelernt, was sie tun) ist die Situation nicht mehr wegzudenken:

    var bind = function(x) {
        return function(y) { return x + y; };
    }
    
    var plus5 = bind(5);
    console.log(plus5(3));

Was hier geschehen würde, wenn JavaScript nicht Verschlüsse wissen? Ersetzen Sie einfach den Anruf in der letzten Zeile von seiner Methode Körper (das ist im Grunde, was Funktionsaufrufe tun), und Sie bekommen:

console.log(x + 3);

Nun, wo ist die Definition von x? Wir haben definieren sie nicht im aktuellen Bereich. Die einzige Lösung ist, lassen plus5 tragen in ihrem Umfang (oder besser gesagt, den Umfang ihrer Eltern) um. Auf diese Weise wird x gut definiert und es wird auf den Wert 5 gebunden ist.

Dies ist ein Versuch, mehrere (mögliche) Missverständnisse über Schließungen zu klären, die in einigen der anderen Antworten erscheinen.

  • Eine Schließung ist nicht nur erstellt, wenn Sie eine innere Funktion zurück. In der Tat, die einschließende Funktion muss nicht überhaupt zurückkehren für die Schließung sein, um erstellt. Sie könnten stattdessen Ihre innere Funktion einer Variablen in einem äußeren Umfang zuweisen oder sie als Argument an eine andere Funktion übergeben, wo sie sofort oder später jederzeit aufgerufen werden. Daher wird die Schließung der umschließenden Funktion wahrscheinlich erstellt , sobald die einschließende Funktion aufgerufen wird, , da jede innere Funktion Zugang zu diesem Verschluss hat, wenn die innere Funktion aufgerufen wird, bevor oder nachdem die einschließende Funktion zurückkehrt.
  • Verschluss nicht eine Kopie der alten Werte von Variablen in ihrem Umfang nicht verweisen. Die Variablen sind selbst Teil des Verschlusses, und so gesehen der Wert beim Zugriff auf einer dieser Variablen ist der neueste Wert zu dem Zeitpunkt auf sie zugegriffen wird. Aus diesem Grund inneren Funktionen innerhalb von Schleifen erstellt schwierig sein kann, da jeder Zugriff auf die gleichen äußeren Variablen hat, anstatt eine Kopie der Variablen zum Zeitpunkt greifen die Funktion erstellt oder genannt.
  • Die „Variablen“ in einem Verschluss umfassen alle genannten Funktionen in der Funktion deklariert. Dazu gehört auch Argumente der Funktion. Ein Verschluss hat auch Zugriff auf die darin enthaltenen Schließung der Variablen, den ganzen Weg zu den globalen Bereich auf.
  • Verschlüsse verwenden Speicher, aber sie verursachen keine Speicherlecks , da JavaScript selbst reinigt seine eigene kreisförmige Strukturen, die nicht referenziert werden. Internet Explorer Speicherlecks die Schließungen erstellt werden, wenn es fehlschlägt DOM trennen Attributwerte, die Verschlüsse verweisen, so dass Hinweise auf möglicherweise Rundbauten beibehalten wird.

OK, 6-jährige Schließungen Fan. Haben Sie das einfachste Beispiel der Schließung hören?

Lassen Sie uns die nächste Situation vorstellen: ein Fahrer in einem Auto sitzt. Das Auto befindet sich in einem Flugzeug. Flugzeug auf dem Flughafen. Die Fähigkeit der Fahrer den Zugriff auf Dinge außerhalb seines Autos, aber in der Ebene, auch wenn das Flugzeug einen Flughafen verlässt, ist ein Verschluss. Das ist es. Wenn Sie 27 drehen, sehen Sie die ausführlichere Erklärung oder am Beispiel unten.

Hier ist, wie kann ich mein Flugzeug Geschichte in den Code umwandeln.

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");

A Schließung ist ähnlich wie ein Objekt. Es wird instanziiert, wenn Sie eine Funktion aufrufen.

Der Umfang der a Schließung in JavaScript ist lexikalisch, was bedeutet, dass alles, was in der Funktion enthalten ist, die Schließung gehört, Zugriff auf jede Variable hat, die in ist es.

Eine Variable enthalten ist in der Schließung , wenn Sie

  1. weisen Sie mit var foo=1; oder
  2. nur schreiben var foo;

Wenn eine innere Funktion (eine Funktion innerhalb einer anderen Funktion enthalten ist) zugreift, eine solche Variable ohne sie in ihrem eigenen Bereich mit var definiert, modifiziert er den Inhalt der Variablen in der äußeren Verschluss .

A Schließung überdauert die Laufzeit der Funktion, die sie hervorgebracht hat. Wenn andere Funktionen, die es aus dem machen Schließung / scope in dem sie definiert sind (zum Beispiel als Rückgabewert), diejenigen Referenz weiterhin, dass Schließung .

Beispiel

function example(closure) {
  // define somevariable to live in the closure of example
  var somevariable = 'unchanged';

  return {
    change_to: function(value) {
      somevariable = value;
    },
    log: function(value) {
      console.log('somevariable of closure %s is: %s',
        closure, somevariable);
    }
  }
}

closure_one = example('one');
closure_two = example('two');

closure_one.log();
closure_two.log();
closure_one.change_to('some new value');
closure_one.log();
closure_two.log();

Ausgabe

somevariable of closure one is: unchanged
somevariable of closure two is: unchanged
somevariable of closure one is: some new value
somevariable of closure two is: unchanged

Ich schrieb ein Blog eine Weile Post zurück Schließungen zu erklären. Hier ist, was ich sagte, über Schließungen in Bezug auf Warum Sie ein wünschen würde.

  

Verschlüsse sind eine Möglichkeit, um eine Funktion zu lassen   haben persistent, private Variablen -   das heißt, Variablen, die nur eine   Funktion kennt, wo er   den Überblick über Informationen aus früheren Zeiten   dass es ausgeführt wurde.

In diesem Sinne ließen sie eine Funktion ein bisschen wie ein Objekt mit einem eigenen Attribute handeln.

Voll Beitrag:

Was sind also diese Schließung thingys

Verschlüsse sind einfach:

Das folgende einfache Beispiel deckt alle wesentlichen Punkte JavaScript Schließungen. *

Hier ist eine Fabrik, die Rechner erzeugt, die addieren und multiplizieren:

function make_calculator() {
  var n = 0; // this calculator stores a single number n
  return {
    add: function(a) {
      n += a;
      return n;
    },
    multiply: function(a) {
      n *= a;
      return n;
    }
  };
}

first_calculator = make_calculator();
second_calculator = make_calculator();

first_calculator.add(3); // returns 3
second_calculator.add(400); // returns 400

first_calculator.multiply(11); // returns 33
second_calculator.multiply(10); // returns 4000

Der entscheidende Punkt: Jeder Aufruf von make_calculator erstellt eine neue lokale Variable n, die von diesem Rechner der add und multiply Funktionen lange nach make_calculator kehrt

verwendbar sein wird fortgesetzt.

Wenn Sie mit Stack-Frames vertraut sind, scheint dieser Rechner seltsam: Wie können sie n nach make_calculator kehrt halten zugreifen? Die Antwort ist, sich vorzustellen, dass JavaScript „Stack Frames“ nicht verwendet, sondern verwendet stattdessen „heap Frames“, die nach dem Funktionsaufruf bestehen können, die aus ihnen zurückkehrt.

Inner-Funktionen wie add und multiply, die in einer äußeren Funktion deklarierten Variablen zugreifen ** , werden als Verschlüsse .

Das ist so ziemlich alles, was es zu Schließungen.



* Zum Beispiel, es umfasst alle Punkte in den "Verschlüssen für Dummies" Artikel gegeben in die akzeptierte Antwort , mit Ausnahme der Punkte (1), die Funktionen ihrer Argumente in lokale Variablen kopieren (die genannten Funktionsargumente), und (2), dass das Kopieren Zahlen erstellt eine neue Nummer, aber das Kopieren eines Objektverweis gibt Ihnen eine weitere Referenz auf das gleiche Objekt. Diese sind auch gut zu wissen, aber wieder völlig unabhängig von Schließungen. Es ist auch sehr ähnlich dem Beispiel in diese Antwort aber etwas kürzer und weniger abstrakt. Es erstreckt sich nicht auf den Punkt der diese Antwort oder dieser Kommentar , das ist, dass JavaScript es schwierig macht, die Strom Wert eines Schleifenvariable zu stopfen in die innere Funktion: Der Schritt „Einstecken“ kann nur mit einer Hilfsfunktion, die Ihre innere Funktion umschließt und wird aufgerufen, auf jeder Schleife Iteration erfolgen. (Streng genommen ist die innere Funktion greift auf die Kopie der Hilfsfunktion der Variablen, anstatt in etwas gesteckt haben.) Auch hier sehr nützlich, wenn Verschlüsse zu schaffen, aber nicht Teil dessen, was eine Schließung ist oder wie es funktioniert. Es gibt zusätzliche Verwirrung aufgrund Verschlüsse arbeiten unterschiedlich in funktionalen Sprachen wie ML, wo Variablen auf Werte gebunden sind und nicht an Stauraum, einen konstanten Strom von Menschen bereitstellt, die Verschlüsse in einer Art und Weise zu verstehen (nämlich die Art und Weise „Einstecken“), das ist einfach falsch für JavaScript, wo Variablen immer an Speicherplatz gebunden, und nie auf Werte.

** Jede äußere Funktion, wenn mehrere verschachtelt sind, oder auch im globalen Kontext, wie

Wie ich es zu einer sechs Jahre alten erklären würde:

Sie wissen, wie Erwachsene ein Haus besitzen können, und sie nennen es nach Hause? Wenn eine Mutter ein Kind hat, das Kind nicht wirklich etwas besitzen, nicht wahr? Aber seine Eltern besitzen ein Haus, so, wenn jemand das Kind fragt: „Wo ist dein Haus?“, Er / sie „das Haus!“ Beantworten können, und zeigen Sie auf das Haus seiner Eltern. A „Closure“ ist die Fähigkeit des Kindes immer (auch im Ausland, wenn) in der Lage sein, zu sagen, es ist ein Zuhause hat, auch wenn es wirklich die Eltern, die das Haus besitzen.

Können Sie erklären, Verschlüsse eine 5-jährige? *

Ich denke immer noch Googles Erklärung funktioniert sehr gut und ist prägnant:

/*
*    When a function is defined in another function and it
*    has access to the outer function's context even after
*    the outer function returns.
*
* An important concept to learn in JavaScript.
*/

function outerFunction(someNum) {
    var someString = 'Hey!';
    var content = document.getElementById('content');
    function innerFunction() {
        content.innerHTML = someNum + ': ' + someString;
        content = null; // Internet Explorer memory leak for DOM reference
    }
    innerFunction();
}

outerFunction(1);​

„Der

* A C # Frage

Ich neige dazu, von GUT / SCHLECHT Vergleichen besser zu lernen. Ich mag, um zu sehen Code von nicht funktionierenden Code gefolgt arbeiten, dass jemand wahrscheinlich zu begegnen. Ich habe zusammen ein jsFiddle , die einen Vergleich tut und versucht, die Unterschiede zu den einfachsten Erklärungen einkochen ich kommen konnte mit.

Verschlüsse richtig gemacht:

console.log('CLOSURES DONE RIGHT');

var arr = [];

function createClosure(n) {
    return function () {
        return 'n = ' + n;
    }
}

for (var index = 0; index < 10; index++) {
    arr[index] = createClosure(index);
}

for (var index in arr) {
    console.log(arr[index]());
}
  • In der obigen Code createClosure(n) wird in jeder Iteration der Schleife aufgerufen. Beachten Sie, dass ich die Variable n Namen hervorzuheben, dass es sich um ein neu Variable in einem neuen Funktion Bereich erstellt und ist nicht die gleiche Variable wie index, die an den äußeren Umfang gebunden ist.

  • Dies schafft einen neuen Rahmen und n in diesem Umfang gebunden ist; dies bedeutet, dass wir 10 separate Bereiche haben, eine für jede Iteration.

  • createClosure(n) gibt eine Funktion, die die n innerhalb dieses Bereichs zurückgibt.

  • In jedem Rahmen n gebunden wird, was auch immer Wert, den es hatte, als createClosure(n) aufgerufen wurde, so dass die verschachtelte Funktion, die immer den Wert von n zurückgegeben wird zurückkehren wird, dass sie hatte, als createClosure(n) aufgerufen wurde.

Verschlüsse falsch gemacht:

console.log('CLOSURES DONE WRONG');

function createClosureArray() {
    var badArr = [];

    for (var index = 0; index < 10; index++) {
        badArr[index] = function () {
            return 'n = ' + index;
        };
    }
    return badArr;
}

var badArr = createClosureArray();

for (var index in badArr) {
    console.log(badArr[index]());
}
  • In dem obigen Code wurde die Schleife innerhalb der createClosureArray() Funktion bewegt und die Funktion kehrt nun gerade das fertige Array, das auf dem ersten Blick scheint intuitiver.

  • Was vielleicht nicht offensichtlich ist, dass seit createClosureArray() nur einmal aufgerufen wird nur ein Rahmen für diese Funktion geschaffen wird, anstatt ein für jede Iteration der Schleife.

  • In dieser Funktion wird eine Variable mit dem Namen index definiert ist. Die Schleife läuft und fügt Funktionen zu der Anordnung, die index zurückzukehren. Beachten Sie, dass index innerhalb der createClosureArray Funktion definiert, die immer nur ein Mal aufgerufen wird.

  • Da es nur ein Rahmen innerhalb der createClosureArray() Funktion war, wird index nur auf einen Wert innerhalb dieses Bereichs gebunden. Mit anderen Worten, jedes Mal ändert sich die Schleife um den Wert von index, es es für alles ändert, dass es innerhalb dieses Bereichs verweist.

  • Alle Funktionen auf dem Array hinzugefügt, um die SAME index Variable aus dem übergeordneten Bereich zurückkehren, wo es statt 10 verschiedene, aus 10 verschiedenen Bereichen wie beim ersten Beispiel definiert wurde. Das Endergebnis ist, dass alle 10 Funktionen die gleiche Variable aus dem gleichen Umfang zurück.

  • Nachdem die Schleife beendet und index wurde der Endwert betrug 10 modifiziert erfolgt daher hinzugefügt jede Funktion auf dem Array gibt den Wert des einzelnen index Variable, die nun auf 10 gesetzt ist.

Ergebnis

  

CLOSURES RECHTS
DONE   n = 0
  n = 1 |   n = 2
  n = 3
  n = 4
  n = 5
  n = 6
  n = 7
  n = 8
  n = 9

     

CLOSURES FALSCH
DONE   n = 10
  n = 10
  n = 10
  n = 10
  n = 10
  n = 10
  n = 10
  n = 10
  n = 10
  n = 10

Wikipedia auf Schließungen :

  

In der Informatik eine Schließung ist eine Funktion zusammen mit einer Referenzierung Umgebung für die nicht-lokalen Namen (freie Variablen) diese Funktion.

Technisch in JavaScript , jede Funktion ist eine Schließung . Es hat immer einen Zugriff auf Variablen in dem umgebenden Bereich definiert.

Da Umfang definierenden Konstruktion in JavaScript eine Funktion ist, , kein Codeblock wie in vielen anderen Sprachen, was wir meinen, in der Regel von Schließung in JavaScript arbeitet eine Funktion mit nicht-lokalen Variablen in bereits ausgeführt umgebender Funktion definiert .

Verschlüsse sind für die Erstellung von Funktionen mit einigen versteckten privaten Daten häufig verwendet (aber es ist nicht immer der Fall ist).

var db = (function() {
    // Create a hidden object, which will hold the data
    // it's inaccessible from the outside.
    var data = {};

    // Make a function, which will provide some access to the data.
    return function(key, val) {
        if (val === undefined) { return data[key] } // Get
        else { return data[key] = val } // Set
    }
    // We are calling the anonymous surrounding function,
    // returning the above inner function, which is a closure.
})();

db('x')    // -> undefined
db('x', 1) // Set x to 1
db('x')    // -> 1
// It's impossible to access the data object itself.
// We are able to get or set individual it.

ems

Das obige Beispiel ist eine anonyme Funktion, die einmal ausgeführt wurde. Aber es muss nicht sein. Es kann (z mkdb) und ausgeführt später genannt werden, eine Datenbankfunktion jedes Mal aufgerufen wird, erzeugt wird. Jede erzeugte Funktion wird sein eigenes verstecktes Datenbankobjekt hat. Ein weiteres Anwendungsbeispiel von Verschlüssen ist, wenn wir nicht über eine Funktion zurück, sondern ein Objekt mehr Funktionen für verschiedene Zwecke, jedes dieser Funktion Zugriff auf die gleichen Daten enthalten.

Ich habe zusammen ein interaktives JavaScript-Tutorial zu erklären, wie Verschlüsse funktionieren. Was ist ein Verschluss?

Hier ist eines der Beispiele:

var create = function (x) {
    var f = function () {
        return x; // We can refer to x here!
    };
    return f;
};
// 'create' takes one argument, creates a function

var g = create(42);
// g is a function that takes no arguments now

var y = g();
// y is 42 here
  

Die Kinder werden immer die Geheimnisse erinnern sie sich mit ihren Eltern geteilt haben, auch nachdem ihre Eltern sind   Weg. Dies ist, was Verschlüsse sind für Funktionen.

Die Geheimnisse für JavaScript-Funktionen sind die privaten Variablen

var parent = function() {
 var name = "Mary"; // secret
}

Jedes Mal, wenn Sie es nennen, lokale Variable „name“ wird erstellt und Vornamen „Mary“. Und jedes Mal, wenn die Funktion die Variable verlässt verloren, und der Name ist vergessen.

Wie Sie sich vorstellen können, weil die Variablen jedes Mal die Funktion aufgerufen wird neu erstellt werden, und niemand sonst weiß sie, muss es ein geheimer Ort, wo sie gespeichert sind. Es könnte genannt werden Kammer des Schreckens oder Stapel oder lokaler Bereich , aber es ist nicht wirklich keine Rolle spielt. Wir wissen, dass sie da sind, irgendwo, in dem Speicher versteckt.

Aber in JavaScript gibt es diese ganz besondere Sache, dass Funktionen, die innerhalb von anderen Funktionen erstellt werden, können auch die lokalen Variablen ihrer Eltern kennen und halten sie so lange, wie sie leben.

var parent = function() {
  var name = "Mary";
  var child = function(childName) {
    // I can also see that "name" is "Mary"
  }
}

Also, solange wir in der übergeordneten -function sind, kann es schaffen einem oder mehr untergeordneten Funktionen, die die geheimen Variablen aus dem geheimen Ort tun teilen.

Aber die traurige Sache ist, wenn das Kind ist auch eine private Variable der übergeordneten Funktion wäre es auch sterben, wenn die Eltern enden, und die Geheimnisse mit ihnen sterben würden.

So zu leben, hat das Kind zu verlassen, bevor es zu spät ist

var parent = function() {
  var name = "Mary";
  var child = function(childName) {
    return "My name is " + childName  +", child of " + name; 
  }
  return child; // child leaves the parent ->
}
var child = parent(); // < - and here it is outside 

Und jetzt, obwohl Maria „nicht mehr läuft“, wird die Erinnerung an sie nicht verloren und ihr Kind wird immer ihren Namen und andere Geheimnisse erinnern sie sich zusammen während ihrer Zeit geteilt.

Wenn Sie also das Kind "Alice" nennen, wird sie antworten

child("Alice") => "My name is Alice, child of Mary"

Das ist alles, was es zu sagen.

Ich verstehe nicht, warum die Antworten hier so komplex sind.

Hier ist ein Verschluss:

var a = 42;

function b() { return a; }

Ja. Sie verwenden wahrscheinlich, dass viele Male am Tag.


  

Es gibt keinen Grund zu glauben, Verschlüsse sind ein komplexes Design Hack zu besonderen Problemen. Nein, Verschlüsse sind nur über eine Variable, die von einem höheren Umfang kommt aus der Perspektive, wo die Funktion erklärt wurde (nicht ausgeführt) .

     

Nun, was es können Sie noch spektakulärer tun sein kann, andere Antworten sehen.

Beispiel für den ersten Punkt durch dlaliberte:

  

Eine Schließung ist nicht nur erstellt, wenn Sie eine innere Funktion zurück. In der Tat, die einschließende Funktion überhaupt nicht zurückkommen müssen. Sie könnten stattdessen Ihre innere Funktion einer Variablen in einem äußeren Umfang zuweisen oder sie als Argument an eine andere Funktion übergeben, wo sie sofort verwendet werden könnten. Es besteht deshalb die Schließung der umschließenden Funktion wahrscheinlich schon zu der Zeit, dass umschließenden Funktion aufgerufen wurde, da jede innere Funktion Zugriff darauf hat, sobald sie aufgerufen wird.

var i;
function foo(x) {
    var tmp = 3;
    i = function (y) {
        console.log(x + y + (++tmp));
    }
}
foo(2);
i(3);

Ein Verschluß ist, wo eine innere Funktion Zugriff auf Variablen in seiner äußeren Funktion hat. Das ist wahrscheinlich die einfachste einzeilige Erklärung Sie für Verschlüsse bekommen.

Ich weiß, es gibt viele Lösungen ist bereits, aber ich denke, dass diese 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

Sie sind mit einem Schlaf über und Sie Dan einladen. Sie Dan sagen, eine XBox-Controller zu bringen.

Dan lädt Paul. Dan fragt Paul einen Controller zu bringen. Wie viele Controller wurden in die Partei gebracht?

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.");

JavaScript-Funktionen können ihren Zugriff:

  1. Argumente
  2. Die Einheimischen (das heißt, ihre lokalen Variablen und lokale Funktionen)
  3. Umwelt, die beinhaltet:
    • Globals, einschließlich der DOM
    • alles in äußeren Funktionen

Wenn eine Funktion seiner Umgebung zugreift, dann die Funktion eine Schließung.

Beachten Sie, dass äußere Funktionen nicht erforderlich sind, wenn sie Vorteile biete ich nicht diskutieren hier. Durch die Daten in seiner Umgebung zugreifen, hält eine Schließung, dass die Daten am Leben. Im Unterfall von außen / innen Funktionen, eine kann äußeree Funktion lokale Daten erstellen und schließlich Ausgang, und doch, wenn eine innere Funktion (en) nach der äußeren Funktion beendet werden überleben, dann ist die innere Funktion (en) hält die lokalen Daten der äußeren Funktion lebendig.

Beispiel eines Verschlusses, der die globale Umwelt verwendet:

Stellen Sie sich vor, dass der Stack-Überlauf Vote-Up und Abstimmen-Down-Taste Ereignisse wie Schließungen umgesetzt werden, voteUp_click und voteDown_click, die den Zugriff auf externe Variablen isVotedUp und isVotedDown haben, die global definiert sind. (Der Einfachheit halber, ich beziehe mich auf die Frage Stackoverflow Vote Buttons, nicht der Anordnung der Antwort Vote Tasten.)

Wenn der Benutzer der VoteUp Schaltfläche klickt, die voteUp_click Funktion prüft, ob isVotedDown == true, um zu bestimmen, ob zu stimmen oder lediglich eine nach unten Abstimmung abzubrechen. Funktion voteUp_click ist ein Verschluss, weil es seine 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 dieser Funktionen sind Verschlüsse, da sie alle ihre Umgebung zugreifen.

Der Autor von Closures hat Verschlüsse ziemlich gut erklärt und erklärt den Grund warum wir sie brauchen und auch erklären LexicalEnvironment, die zum Verständnis der Verschlüsse erforderlich ist.
Hier ist die Zusammenfassung:

Was passiert, wenn eine Variable zugegriffen wird, aber es ist nicht lokal? Wie hier:

 Gib Bild Beschreibung hier

In diesem Fall findet der Interpreter die Variable in der Außen LexicalEnvironment Objekt.

Das Verfahren besteht aus zwei Schritten:

  1. Erstens, wenn eine Funktion f erstellt wird, wird es nicht in einem leeren erstellt Platz. Es gibt ein aktuelles LexicalEnvironment Objekt. Im Falle oben, es ist Fenster (a zum Zeitpunkt der Funktion nicht definiert ist Schöpfung).

 Gib Bild Beschreibung hier

Wenn eine Funktion erstellt wird, wird es eine versteckte Eigenschaft, [[Scope]] genannt, die den aktuellen LexicalEnvironment verweist.

 Gib Bild Beschreibung hier

Wenn eine Variable gelesen wird, kann aber nicht überall gefunden werden, wird ein Fehler erzeugt wird.

Verschachtelte Funktionen

Funktionen können ineinander verschachtelt werden, eine Kette von LexicalEnvironments bildet, kann auch ein Rahmen Kette genannt werden.

 Gib Bild Beschreibung hier

So Funktion g hat Zugriff auf g, a und f.

Verschlüsse

Eine verschachtelte Funktion weiterhin leben, nachdem die äußere Funktion beendet hat:

 Gib Bild Beschreibung hier

Markierung bis LexicalEnvironments:

 Gib Bild Beschreibung hier

Wie wir sehen, this.say ist eine Eigenschaft in dem Benutzerobjekt, so geht es weiter nach Benutzer leben abgeschlossen.

Und wenn Sie sich erinnern, wenn this.say erstellt wird, es (wie jede Funktion) erhält eine interne Referenz this.say.[[Scope]] auf den aktuellen LexicalEnvironment. So bleibt der LexicalEnvironment der aktuellen Benutzer Ausführung im Speicher. Alle Variablen der Benutzer sind auch seine Eigenschaften, so dass sie auch sorgfältig aufbewahrt, nicht wie sonst üblich weggeschmissen.

Der springende Punkt ist, um sicherzustellen, dass, wenn die innere Funktion eine äußeree Variable in der Zukunft zugreifen will, es in der Lage ist, dies zu tun.

Um es zusammenzufassen:

  1. die innere Funktion hält eine Referenz auf den äußeren LexicalEnvironment.
  2. Die inneren Funktionsvariablen aus darauf zugreifen können jederzeit, auch wenn die äußere Funktion beendet ist.
  3. Der Browser hält die LexicalEnvironment und alle seine Eigenschaften (Variablen) im Speicher, bis es eine innere Funktion ist, die es verweist.

Dies ist eine Schließung genannt.

Als Vater eines 6-jährigen, die derzeit Unterrichten junger Kinder (und einer relativen Anfänger ohne formale Ausbildung Codierung so werden Korrekturen erforderlich sein), ich denke, die Lektion am besten durch Hands-on-Spiel bleiben würde. Wenn die 6-Jährige ist bereit, zu verstehen, was ein Verschluss ist, dann sind sie alt genug, um eine sich gehen. Ich würde vorschlagen, den Code in jsfiddle.net, erklärt ein wenig einfügen, und ließ sich allein ein einzigartiges Lied brauen. Der erläuternde Text ist wahrscheinlich besser geeignet für eine 10 Jahre alt.

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);

Anleitung

DATA: Daten sind eine Sammlung von Fakten. Es kann Zahlen, Wörter, Messungen, Beobachtungen oder auch nur Beschreibungen der Dinge. Sie können es nicht berühren, riechen oder schmecken. Sie können es aufschreiben, sprechen sie und es hören. Man könnte es zu verwenden erstellen Touch Geruch und Geschmack mit einem Computer. Es kann durch einen Computer unter Verwendung von Code nutzbar gemacht werden.

CODE: Alle Schrift oben genannt wird Code . Es steht geschrieben in JavaScript.

javascript: JavaScript ist eine Sprache. Wie Englisch oder Französisch oder Chinesisch sind Sprachen. Es gibt viele Sprachen, die von Computern und anderen elektronischen Prozessoren verstanden werden. Für JavaScript von einem Computer verstanden werden muss es einen Dolmetscher. Stellen Sie sich vor, wenn ein Lehrer, der Russisch spricht nur darum geht, Ihre Klasse in der Schule zu unterrichten. Wenn der Lehrer sagt: „все садятся“, würde die Klasse nicht verstehen. Aber zum Glück haben Sie einen russischen Schüler in der Klasse, die jeden sagt, das bedeutet „jeder hinsetzen“ - so dass Sie alle tun. Die Klasse ist wie ein Computer und die russischen Schüler sind der Dolmetscher. Für JavaScript, um die am häufigsten Interpreter ist ein Browser aufgerufen.

BROWSER: Wenn Sie mit dem Internet auf einem Computer, Tablet oder Telefon verbinden, eine Website zu besuchen, benutzen Sie einen Browser. Beispiele, die Sie vielleicht wissen, sind Internet Explorer, Chrome, Firefox und Safari. Der Browser kann JavaScript verstehen und dem Computer sagen, was sie tun soll. Die JavaScript-Anweisungen werden als Funktionen.

FUNKTION: Eine Funktion in JavaScript wie eine Fabrik. Es könnte mit nur einer Maschine in eine kleine Fabrik sein. Oder es könnte viele andere kleine Fabriken enthält, die jeweils mit vielen Maschinen verschiedene Jobs zu tun. In einer realen Leben Kleidung Fabrik könnten Sie Unmengen von Stoffe und Spulen des Thread haben, die in und T-Shirts und Jeans herauskommen. Unsere JavaScript Fabrik verarbeitet nur Daten, kann es kein Loch oder Metall näht, bohren schmelzen. In unseren Daten JavaScript Fabrik geht in und Daten kommen.

All diese Daten Zeug klingt ein bisschen langweilig, aber es ist wirklich sehr cool; wir könnten eine Funktion haben, die einen Roboter sagt, was für das Abendessen zu machen. Sagen wir, ich lade Sie und Ihr Freund zu mir nach Hause. Sie mögen Hühnerbeine am besten, Ich mag Würstchen, Ihr Freund will immer, was Sie wollen und mein Freund essen kein Fleisch.

Ich habe keine Zeit, einkaufen zu gehen, so dass die Funktion muss wissen, was wir im Kühlschrank haben, Entscheidungen zu treffen. Jede Zutat hat eine andere Kochzeit und wir wollen, dass alles durch den Roboter zur gleichen Zeit heiß serviert werden. Wir brauchen die Funktion mit der Daten über das, was wir wollen, ist die Funktion könnte ‚sprechen‘ an den Kühlschrank, und die Funktion kann den Roboter steuern.

Eine Funktion hat in der Regel einen Namen, Klammern und Klammern. Wie folgt aus:

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

Beachten Sie, dass /*...*/ und // Stop-Code vom Browser gelesen werden.

NAME: Sie können eine Funktion rufen Sie über das, was Wort, das Sie wollen. Das Beispiel „cookMeal“ ist typisch für die Verbindung von zwei Worten zusammen und den zweiten einen Großbuchstaben am Anfang zu geben - aber das ist nicht notwendig. Es kann keinen Raum in ihm hat, und es kann nicht eine Nummer auf seinem eigenen sein.

Klammern: „Klammern“ oder () sind die Briefkasten auf der JavaScript-Funktion Fabrik Tür oder einen Briefkasten auf der Straße für Pakete von Informationen an die Fabrik zu schicken. Manchmal ist die PostBox markiert werden könnte zum Beispiel cookMeal(you, me, yourFriend, myFriend, fridge, dinnerTime), wobei in diesem Fall wissen Sie, welche Daten Sie haben es zu geben.

BRACES: „Zahnspange“, die wie dieses aussehen {} sind die getönten Scheiben unserer Fabrik. Aus dem Innern der Fabrik kann man sehen, aber von außen kann man nicht sehen, in.

THE LONG CODE Beispiel oben

Unser Code beginnt mit dem Wort Funktion , so dass wir wissen, dass es eine ist! Dann wird der Name der Funktion singen - das ist meine eigene Beschreibung dessen, was die Funktion geht. Dann Klammern () . Die Klammern sind immer für eine Funktion. Manchmal sind sie leer, und manchmal haben sie etwas in diesen ein Wort hat in:. (person). Danach gibt es eine Klammer wie diese {. Dies markiert den Start der Funktion singen () . Es hat einen Partner, der das Ende von singen () wie diese } markiert

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

Also diese Funktion etwas mit Singen zu tun haben könnte, und möglicherweise einige Daten über eine Person benötigen. Es hat innerhalb Anweisungen etwas mit diesen Daten zu tun.

Jetzt, nach der Funktion singen () , in der Nähe des Ende des Codes ist die Zeile

var person="an old lady";

VARIABLE: Die Buchstaben var steht für "Variable". Eine Variable ist wie ein Umschlag. Auf der Außenseite wird diese Hülle „Person“ gekennzeichnet. Auf der Innenseite enthält es ein Zettel mit den Informationen unserer Funktion benötigt, einige Buchstaben und Leerzeichen zusammengefügt wie ein Stück Schnur, die einen Satz liest „eine alte Dame“ zu machen (es einen String genannt). Unser Umschlag andere Arten von Dingen wie Zahlen enthalten könnte (so genannte ganze Zahlen), Anweisungen (so genannte Funktionen), Listen (die so genannten Arrays ). Da diese Variable außerhalb aller Klammern {} geschrieben, und weil man durch die getönten Scheiben sieht aus, wenn Sie in den geschweiften Klammern sind, kann diese Variable von überall im Code zu sehen. Wir nennen dies eine 'globale Variable'.

globale Variable: Person ist eine globale Variable, was bedeutet, dass, wenn Sie seinen Wert von "einer alten Dame" zu "einem jungen Mann", die Person halten wobei ein junger Mann, bis Sie es wieder ändern und dass jede andere Funktion in dem Code kann sehen, dass es ein junger Mann ist. Drücken Sie die F12 Taste oder Blick auf die Optionen Einstellungen, um die Entwickler-Konsole von einem Browser zu öffnen und geben Sie „Person“ zu sehen, was dieser Wert ist. Geben Sie person="a young man" es zu ändern und geben Sie dann „Person“ wieder zu sehen, dass sie sich geändert hat.

Danach haben wir die Linie

sing(person);

Diese Linie die Funktion aufruft, als ob es einen Hund rief

  

"Komm singen , Komm und hol Person "

Wenn der Browser den JavaScript-Code ein diese Zeile erreicht geladen ist, wird es die Funktion starten. Ich habe die Linie am Ende, um sicherzustellen, dass der Browser alle benötigten Informationen hat, um sie auszuführen.

Funktionen definieren Aktionen - die Hauptfunktion ist über das Singen. Es enthält eine Variable mit dem Namen firstPart , die über die Person, den Gesang gilt, das jedem des Verses des Liedes gilt: „Es gab“ + Person + „die verschluckt“. Wenn Sie geben firstPart in die Konsole, werden Sie keine Antwort erhalten, da die Variablen nach oben in einer Funktion gesperrt -. Der Browser kann nicht in den getönten Scheiben der Streben sehen

CLOSURES: Die Verschlüsse sind die kleineren Funktionen, die in der großen sind singen () Funktion. Die kleinen Fabriken in der großen Fabrik. Sie haben jeweils ihre eigenen Streben, die bedeuten, dass die Variablen in ihnen nicht von außen gesehen werden. Deshalb sind die Namen der Variablen ( Kreatur und Ergebnis ) können in den Verschlüssen wiederholt werden, aber mit unterschiedlichen Werten. Wenn Sie diese Variablennamen in dem Konsolenfenster eingeben, werden Sie nicht seinen Wert, weil sie von zwei Schichten von ti verstecktnted Fenster.

Die Verschlüsse alle wissen, was die singen () Funktion der Variable mit dem Namen firstPart ist, weil sie von ihren getönten Scheiben sehen können.

Nachdem die Verschlüsse kommen die Linien

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

Die singen () Funktion wird jede dieser Funktionen in der Reihenfolge nennen sie gegeben sind. Dann wird die Sing () Funktion der Arbeit getan werden.

Okay, im Gespräch mit einem 6-jährigen Kind, würde ich möglicherweise folgende Verbände verwendet werden.

  

Stellen Sie sich vor - Sie mit Ihren kleinen Brüdern und Schwestern im ganzen Hause spielen, und Sie bewegen sich mit Ihrem Spielzeug und einige von ihnen in Ihren älteren Bruder Zimmer gebracht. Nach einer Weile kehrte dein Bruder von der Schule und ging in sein Zimmer, und er in ihn verschlossen, so dass jetzt konnte man nicht Spielzeug auf direktem Weg mehr da Zugriff auf links. Aber man konnte die Tür klopfen und fragen Sie Ihren Bruder für das Spielzeug. Dies wird als Spielzeug der Schließung ; Ihr Bruder machte es für Sie, und er ist jetzt in die äußere Anwendungsbereich .

mit einer Situation vergleichen, wenn eine Tür von Entwurf und niemand innen verriegelt wurde (allgemeine Funktionsausführung), und dann einige lokale Feuer auftreten und abbrennen den Raum (Garbage Collector: D), und dann wird ein neuer Raum gebaut wurde und jetzt Sie ein anderes Spielzeug gibt (neue Funktion Instanz) verlassen kann, aber nie die gleichen Spielsachen bekommen, die im ersten Raum Instanz gelassen wurde.

Für eine erweiterte Kind würde ich so etwas wie die folgenden stellen. Es ist nicht perfekt, aber es fühlt man sich über das, was es ist:

function playingInBrothersRoom (withToys) {
  // We closure toys which we played in the brother's room. When he come back and lock the door
  // your brother is supposed to be into the outer [[scope]] object now. Thanks god you could communicate with him.
  var closureToys = withToys || [],
      returnToy, countIt, toy; // Just another closure helpers, for brother's inner use.

  var brotherGivesToyBack = function (toy) {
    // New request. There is not yet closureToys on brother's hand yet. Give him a time.
    returnToy = null;
    if (toy && closureToys.length > 0) { // If we ask for a specific toy, the brother is going to search for it.

      for ( countIt = closureToys.length; countIt; countIt--) {
        if (closureToys[countIt - 1] == toy) {
          returnToy = 'Take your ' + closureToys.splice(countIt - 1, 1) + ', little boy!';
          break;
        }
      }
      returnToy = returnToy || 'Hey, I could not find any ' + toy + ' here. Look for it in another room.';
    }
    else if (closureToys.length > 0) { // Otherwise, just give back everything he has in the room.
      returnToy = 'Behold! ' + closureToys.join(', ') + '.';
      closureToys = [];
    }
    else {
      returnToy = 'Hey, lil shrimp, I gave you everything!';
    }
    console.log(returnToy);
  }
  return brotherGivesToyBack;
}
// You are playing in the house, including the brother's room.
var toys = ['teddybear', 'car', 'jumpingrope'],
    askBrotherForClosuredToy = playingInBrothersRoom(toys);

// The door is locked, and the brother came from the school. You could not cheat and take it out directly.
console.log(askBrotherForClosuredToy.closureToys); // Undefined

// But you could ask your brother politely, to give it back.
askBrotherForClosuredToy('teddybear'); // Hooray, here it is, teddybear
askBrotherForClosuredToy('ball'); // The brother would not be able to find it.
askBrotherForClosuredToy(); // The brother gives you all the rest
askBrotherForClosuredToy(); // Nothing left in there

Wie Sie sehen können, das Spielzeug in dem Raum links ist noch erreichbar über den Bruder und unabhängig davon, ob der Raum gesperrt ist. Hier ist ein jsbin mit ihm zu spielen, um.

Eine Antwort für eine sechsjährige (vorausgesetzt, er weiß, was eine Funktion ist und was eine Variable ist, und welche Daten):

Funktionen können Daten zurück. Eine Art von Daten, die Sie aus einer Funktion zurückgeben kann, ist eine andere Funktion. Wenn diese neue Funktion zurückgegeben wird, werden alle Variablen und Argumente in der Funktion verwendet, die sie geschaffen gehen nicht weg. Stattdessen „wird geschlossen.“, Dass übergeordnete Funktion Mit anderen Worten, in der es nichts gibt die Variablen und sieht es mit Ausnahme der Funktion verwendete es zurückgegeben. Diese neue Funktion hat eine besondere Fähigkeit, innerhalb der Funktion zurück zu blicken, die sie geschaffen und sieht die Daten im Innern.

function the_closure() {
  var x = 4;
  return function () {
    return x; // Here, we look back inside the_closure for the value of x
  }
}

var myFn = the_closure();
myFn(); //=> 4

Eine andere wirklich einfache Art und Weise zu erklären, ist in Umfang:

Jedes Mal, wenn Sie innerhalb eines größeren Umfangs einen kleineren Umfang erstellen, wird der kleinere Rahmen immer in der Lage sein zu sehen, was in dem größeren Umfang ist.

Eine Funktion in JavaScript ist nicht nur ein Verweis auf eine Reihe von Anweisungen (wie in der C-Sprache), aber es enthält auch eine verborgene Datenstruktur, die von Referenzen auf alle nicht lokalen Variablen zusammengesetzt ist, verwendet es (erfassten Variablen). Eine solche zweiteilige Funktionen Verschlüsse genannt. Jede Funktion in JavaScript kann eine Schließung in Betracht gezogen werden.

Verschlüsse sind Funktionen mit einem Zustand. Es ist etwas ähnlich wie „this“ in dem Sinne, dass „dies“ auch Zustand für eine Funktion, sondern Funktion und „this“ sind separate Objekte ( „this“ bietet, ist nur ein schicker Parameter, und der einzige Weg, sie zu binden, dauerhaft einen Funktion ist es, einen Verschluß zu schaffen). Während „diese“ und Funktion immer getrennt lebt, kann eine Funktion nicht von seiner Schließung getrennt werden und die Sprache sieht keine Mittel zur erfassten Variablen zuzugreifen.

Da alle diese externen Variablen durch eine lexikalisch verschachtelte Funktion verwiesen wird, tatsächlich lokale Variablen in der Kette seiner lexikalisch umgebenden Funktionen sind (globale Variablen angenommen werden, können lokale Variablen einiger Wurzelfunktion sein), und jede einzelne Ausführung einer Funktion erstellt neue Instanzen der lokalen Variablen, so folgt daraus, dass jede Ausführung einer Funktion zurückkehrt (oder sonst ist es aus, wie es als Rückruf Übertragung Registrierung) eine verschachtelte Funktion erstellt einen neuen Verschluss (mit einem eigenen potentiell einzigartigen Satz von referenzierten nonlocal Variablen, die repräsentiert seinen Ausführungskontext).

Außerdem muss klar sein, dass lokale Variablen in JavaScript erstellt werden nicht auf dem Stack-Frame, aber auf dem Heap und zerstört nur, wenn niemand sie verweist. Wenn eine Funktion zurück, Verweise auf seine lokalen Variablen verringert werden, aber sie können immer noch nicht null sein, wenn während der aktuellen Ausführung sie Teil eines Verschlusses wurden und werden immer noch durch seine lexikalisch verschachtelte Funktionen verwiesen wird (was nur dann, wenn die Referenzen passieren kann diese verschachtelten Funktionen zurückgegeben wurden oder auf andere Weise zu einem externen Code übertragen).

Ein Beispiel:

function foo (initValue) {
   //This variable is not destroyed when the foo function exits.
   //It is 'captured' by the two nested functions returned below.
   var value = initValue;

   //Note that the two returned functions are created right now.
   //If the foo function is called again, it will return
   //new functions referencing a different 'value' variable.
   return {
       getValue: function () { return value; },
       setValue: function (newValue) { value = newValue; }
   }
}

function bar () {
    //foo sets its local variable 'value' to 5 and returns an object with
    //two functions still referencing that local variable
    var obj = foo(5);

    //Extracting functions just to show that no 'this' is involved here
    var getValue = obj.getValue;
    var setValue = obj.setValue;

    alert(getValue()); //Displays 5
    setValue(10);
    alert(getValue()); //Displays 10

    //At this point getValue and setValue functions are destroyed
    //(in reality they are destroyed at the next iteration of the garbage collector).
    //The local variable 'value' in the foo is no longer referenced by
    //anything and is destroyed too.
}

bar();

Vielleicht ein wenig über alle, aber die meisten altklug von sechs-Jährigen, aber ein paar Beispiele, die das Konzept der Schließung in JavaScript klicken für mich gemacht haben.

Eine Schließung ist eine Funktion, die den Zugriff auf eine andere Funktion des Oszilloskops (seine Variablen und Funktionen) hat. Der einfachste Weg, um einen Verschluss zu schaffen, ist mit einer Funktion innerhalb einer Funktion; Der Grund dafür ist, dass in JavaScript eine Funktion jederzeit Zugriff auf die darin enthaltenen Funktion des Oszilloskops hat.

function outerFunction() {
    var outerVar = "monkey";
    
    function innerFunction() {
        alert(outerVar);
    }
    
    innerFunction();
}

outerFunction();

ALERT: Affe

Im obigen Beispiel wird outerFunction aufgerufen, die wiederum ruft innerFunction. Beachten Sie, wie outerVar zu innerFunction verfügbar ist, belegt durch seinen korrekten Wert von outerVar aufmerksam zu machen.

Betrachten wir nun wie folgt vor:

function outerFunction() {
    var outerVar = "monkey";
    
    function innerFunction() {
        return outerVar;
    }
    
    return innerFunction;
}

var referenceToInnerFunction = outerFunction();
alert(referenceToInnerFunction());

ALERT: Affe

referenceToInnerFunction wird auf outerFunction (), die einfach einen Verweis auf innerFunction zurückgibt. Wenn referenceToInnerFunction aufgerufen wird, gibt es outerVar. Wieder, wie oben, dies zeigt, dass innerFunction Zugriff auf outerVar hat, eine Variable outerFunction. Darüber hinaus ist es interessant festzustellen, dass es diesen Zugriff behält auch nach outerFunction Ausführung beendet hat.

Und hier ist, wo die Dinge wirklich interessant. Wenn wir loswerden outerFunction waren, sagen Sie es auf null gesetzt, könnte man denken, dass referenceToInnerFunction seinen Zugriff auf den Wert von outerVar verlieren würde. Aber dies 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 wie ist das so? Wie kann referenceToInnerFunction wissen immer noch den Wert von outerVar jetzt, dass outerFunction eingestellt wurde auf null?

Der Grund, dass referenceToInnerFunction noch den Wert von outerVar zugreifen kann, ist, weil, wenn der Verschluss erste innerFunction erstellt wurde innerhalb von outerFunction indem, innerFunction einen Verweis auf outerFunction Anwendungsbereich (seine Variablen und Funktionen) hinzugefügt, um ihren Umfang Kette. Das bedeutet, dass innerFunction einen Zeiger oder Verweis auf alle outerFunction der Variablen, einschließlich outerVar hat. Also selbst wenn outerFunction beendet ausgeführt wird, oder selbst wenn sie gelöscht oder auf Null gesetzt, die Variablen in ihrem Umfang, wie outerVar, bleiben, um im Speicher wegen der hervorragenden auf sie Bezug auf den Teil des innerFunction, die zurückgegeben wurde referenceToInnerFunction. Um wirklich outerVar zu lösen und den Rest outerFunction die Variablen aus dem Speicher würden Sie diesen herausragenden Bezug auf sie loswerden müssen, etwa durch referenceToInnerFunction Einstellung als auch auf null.

//////////

Zwei weitere Dinge über Schließungen zu beachten. Erstens haben die Schließung wird immer Zugriff auf die letzten Werte seiner Funktion enthält.

function outerFunction() {
    var outerVar = "monkey";
    
    function innerFunction() {
        alert(outerVar);
    }
    
    outerVar = "gorilla";

    innerFunction();
}

outerFunction();

ALERT: Gorilla

Zweitens, wenn ein Verschluss erstellt wird, behält es einen Hinweis auf alle seine einschließende Funktion der Variablen und Funktionen; wird es nicht zu wählen, und zu wählen. Und doch so, Verschlüsse sollten sparsam oder zumindest vorsichtig verwendet werden, da sie speicherintensiv sein kann; eine Menge von Variablen kann lange, nachdem eine Funktion enthält, hat die Ausführung beendet.

im Speicher gehalten werden,

Ich würde sie einfach auf den Mozilla Closures zeigen. Es ist das beste, präzise und einfache Erklärung Verschlussgrundlagen und praktische Anwendung, die ich gefunden habe. Es wird dringend jemand Lernen JavaScript empfohlen.

Und ja, ich würde es sogar zu einem 6jährigen empfehlen - wenn die 6-Jährige über Schließungen zu lernen, dann logisch ist es, sie sind bereit, die präzise und einfache Erklärung zu verstehen, in dem Artikel zur Verfügung gestellt.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top