Einführung
Ein Verschluss ist eine Funktion, die die Erlaubnis hat, in einem anderen Funktionsbereich auf Variablen zuzugreifen.
Schließungen sind in JavaScript schwer zu verstehen. Viele erweiterte Anwendungen stützen sich auf Schließungen, um sie umzusetzen. Schauen wir uns zuerst ein Beispiel unten an:
Funktion ober () {var i = 100; Funktion inner () {console.log (i); }}Im obigen Code sind gemäß dem Umfang der Variablen alle lokalen Variablen in der Außenfunktion für die innere Funktion sichtbar. Lokale Variablen in der inneren Funktion sind außerhalb der inneren Funktion unsichtbar, sodass lokale Variablen in der inneren Funktion nicht außerhalb der inneren Funktion gelesen werden können.
Da die innere Funktion die lokalen Variablen der äußeren Funktion lesen kann, können die inneren lokalen Variablen direkt außerhalb des OUer gelesen werden, solange das innere als Rückgabewert verwendet wird.
Funktion ober () {var i = 100; Funktion inner () {console.log (i); } return Inner;} var rs = outer ();Diese Funktion hat zwei Eigenschaften:
Nach der Ausführung von var rs = äußer () zeigt der tatsächliche RS -RS auf die innere Funktion. Dieser Code ist eigentlich eine Schließung. Das heißt, wenn die Funktion innerhalb der Außenfunktion durch eine Variable außerhalb der Außenfunktion in der Funktion referenziert wird, wird ein Verschluss erzeugt.
Umfang
Einfach ausgedrückt ist der Umfang der zugängliche Bereich von Variablen und Funktionen, dh, kontrolliert Geltungsbereich die Sichtbarkeit und den Lebenszyklus von Variablen und Funktionen. In JavaScript ist der Umfang der Variablen global und lokal.
Globaler Umfang
var num1 = 1; Funktion fun1 () {Num2 = 2;}Die obigen drei Objekte Num1, Num2 und Fun1 sind alle globale Bereiche. Es ist hier zu beachten, dass die Variablen, die direkte Zuordnungen am Ende definieren, automatisch als globale Bereiche deklariert werden.
Lokaler Bereich
Funktion Wrap () {var obj = "Ich bin von Wrap abgeschlossen, und die Außenseite von Wrap kann nicht direkt auf mich zugreifen"; Funktion Innerfun () {// Außen kann nicht auf mich zugreifen}}Bereichskette
Alles in JavaScript ist ein Objekt. Diese Objekte haben eine [[Scope]] Eigenschaft, die eine Sammlung von Objekten in dem von der Funktion erstellten Bereich enthält. Diese Sammlung wird als Scope -Kette der Funktion bezeichnet, die bestimmt, auf welche Daten von der Funktion zugegriffen werden können.
Funktion add (a, b) {return a+b;}Wenn eine Funktion erstellt wird
var sum = add (3,4);
Wenn eine Funktion aufgerufen wird, wird ein internes Objekt erstellt, das als Ausführungskontext bezeichnet wird. Dieses Objekt Z definiert die Umgebung, wenn die Funktion ausgeführt wird. Es hat auch eine eigene Zielfernrohrkette für die Auflösung von Identifikatoren, und seine Bereichskette wird als Objekt initialisiert, das in [[Scope]] der aktuellen Lauffunktion enthalten ist.
Während der Funktionsausführung wird jedes Mal, wenn eine Variable auftritt, ein Identifikator -Parsenprozess übergeben, um zu entscheiden, wo Daten erhalten und gespeichert werden sollen. Dieser Vorgang beginnt vom Kopf der Bereichskette, dh nach einem gleichnamigen Bezeichner des aktiven Objekts. Wenn es gefunden wird, verwenden Sie die Variable, die dieser Kennung entspricht. Wenn es nicht gefunden wird, suchen Sie weiter nach dem nächsten Objekt in der Bereichskette, wenn alle Objekte durchsucht werden (das letzte ist ein globales Objekt), wird die Kennung als nicht definiert angesehen.
Schließung
Ein Verschluss ist einfach eine Funktion, die auf die externen Variablen zugreift.
var quo = function (Status) {return {getStatus: function () {return status; }}}Der Status wird in Quo gespeichert. Es gibt ein Objekt zurück, die Methode GetStatus in diesem Objekt bezieht sich auf die Statusvariable, dh auf die GetStatus -Funktion zugänglich, auf den externen Variablenstatus.
var newValue = quo ('String'); // Rückgabe eines anonymen Objekts, auf das von NewValue mit NewValue.getStatus () verwiesen; // Zugriff auf den internen Variablenstatus von Quo zugegriffen hatWenn die GetStatus -Methode nicht verfügbar ist, wird der Status nach Quo ('Sting') automatisch recycelt. Gerade weil das zurückgegebene anonyme Objekt von einem globalen Objekt referenziert wird und das anonyme Objekt vom Status abhängt, verhindern es die Freigabe des Status.
Beispiel:
// Fehlerschema var test = Funktion (Knoten) {var i; für (i = 0; i <nodes.length; i ++) {nodes [i] .onclick = function (e) {alert (i); }}}Eine anonyme Funktion schafft einen Verschluss, und das I -Zugriff ist ich in der externen Testfunktion, sodass jeder Knoten tatsächlich auf das gleiche i bezieht.
// Verbesserungslösung var test = Funktion (Knoten) {var i; für (i = 0; i <nodes.length; i ++) {nodes [i] .onclick = function (i) {return function () {alert (i); }; }(ich); }}Jeder Knoten ist an ein Ereignis gebunden. Dieses Ereignis empfängt einen Parameter und wird sofort ausgeführt, wobei I. Da es mit Wert übergeben wird, generiert jede Schleife eine neue Sicherung für das aktuelle i.
Die Rolle der Schließung
Funktion ober () {var i = 100; Funktion inner () {console.log (i ++); } return Inner;} var rs = outer (); // 100rs (); // 101rs (); // 102Im obigen Code ist RS die innere Funktion des Verschlusses. RS lief insgesamt dreimal, das erste Mal war 100, das zweite Mal 101 und das dritte Mal 102. Dies zeigt, dass die lokale Variable I in der äußeren Funktion im Speicher gehalten wurde und nicht automatisch gelöscht wurde, wenn er aufgerufen wurde.
Der Zweck des Verschlusses ist, dass nach Abschluss der Außenausführung und zurückgegeben wird, der Verschluss den Müllmechanismus des JavaScripts (die Sammlung Grab -Sammlung) nicht recycelt, da der von der Außenausführung besetzte Gedächtnis, da die Ausführung der inneren Funktion der Außenübernahme abhängt. (Eine weitere Erklärung: Außen ist die übergeordnete Funktion des inneren, das innere wird einer globalen Variablen zugeordnet, was die ganze Zeit im Gedächtnis im Gedächtnis hat, und die Existenz von Innere hängt von der Außenseite ab, da einige Außen immer im Speicher sind und nicht nach Abschluss des Anrufs abgeschlossen sind.
Der Verschluss hat die Erlaubnis, auf alle Variablen innerhalb der Funktion zuzugreifen.
Wenn eine Funktion einen Verschluss zurückgibt, wird der Umfang der Funktion im Speicher gespeichert, bis der Verschluss nicht vorhanden ist.
Schließungen und Variablen
Aufgrund des Umfangskettenmechanismus kann der Verschluss nur den letzten Wert erhalten, der eine Variable in der Funktion enthält. Siehe das folgende Beispiel:
Funktion f () {var rs = []; für (var i = 0; i <10; i ++) {rs [i] = function () {return i; }; } return rs;} var fn = f (); für (var i = 0; i <fn.length; i ++) {console.log ('Funktion fn [' + i + '] () Rückgabewert:' + fn [i] ());}Funktionen geben ein Array zurück. Auf der Oberfläche scheint es, dass jede Funktion ihren eigenen Indexwert zurückgeben sollte. Tatsächlich gibt jede Funktion 10 zurück. Dies liegt daran, dass die Bereichskette der ersten Funktion die aktiven Funktionen der Funktion F enthält und sich auf dieselbe Variable i beziehen. Wenn die Funktion f zurückgibt, beträgt der Wert der Variablen I 10. Zu diesem Zeitpunkt speichert jede Funktion das gleiche variable Objekt der Variablen i. Wir können die Schließung erzwingen, sich wie erwartet zu verhalten, indem wir eine andere anonyme Funktion erstellen.
Funktion f () {var rs = []; für (var i = 0; i <10; i ++) {rs [i] = function (num) {return function () {return num; }; }(ich); } return rs;} var fn = f (); für (var i = 0; i <fn.length; i ++) {console.log ('Funktion fn [' + i + '] () Rückgabewert:' + fn [i] ());}In dieser Version definieren wir, anstatt den Verschluss direkt dem Array, eine anonyme Funktion zuzuweisen und dem Array das Ergebnis der sofortigen Ausführung der anonymen Funktion zuweisen. Hier hat die anonyme Funktion einen Parameterum. Wenn wir jede Funktion aufrufen, geben wir die Variable i über. Da die Parameter mit einem Wert übergeben werden, wird die Variable, die ich an den Parameter num kopiert wird. In dieser anonymen Funktion wird ein Verschluss auf NUM erstellt und zurückgegeben. Auf diese Weise hat jede Funktion im RS -Array eine Kopie ihrer eigenen Num -Variablen, sodass verschiedene Werte zurückgegeben werden können.
Dieses Objekt im Abschluss
var name = 'Jack'; var o = {name: 'bingdian', getName: function () {return function () {return this.name; }; }} console.log (o.getName () () ()); // Jackvar name = 'Jack'; var o = {name: 'bingdian', getName: function () {var self = this; return function () {return self.name; }; }} console.log (o.getName () () ()); // BingdianSpeicherleck
Funktion ordnungsgemäß () {var el = document.getElementById ('Demo'); el.onclick = function () {console.log (el.id); }} ordnungsgemäß ();Der obige Code erzeugt einen Verschluss als Ereignishandler von EL -Elementen, und dieser Verschluss erzeugt eine kreisförmige Referenz. Solange die anonyme Funktion existiert, beträgt die Anzahl der EL -Referenzen mindestens 1, da die von ihr belegte Erinnerung niemals recycelt wird.
Funktion ordnungsgemäß () {var el = document.getElementById ('Demo'); var id = el.id; el.onclick = function () {console.log (id); } el = null;} ordnungsgemäß ();Durch das Einstellen der variablen El Null können Sie das DOM -Objekt Dereference und sicherstellen, dass der Speicher normal verbraucht.
Imitieren Sie den Umfang auf Blockebene
Die in einem Paar lockigen Klammern ({und}) festgelegten Anweisung gehört zu einem Block, und alle darin definierten Variablen sind außerhalb des Codeblocks unsichtbar, den wir als Umfang auf Blockebene bezeichnen.
(function () {// Block-Level Scope}) ();Anwendung von Schließungen
Schützen Sie die Sicherheit von Variablen in der Funktion. Wie im vorherigen Beispiel kann nur auf die innere Funktion auf I zugreifen, die in der äußeren Funktion zugreifen kann, aber nicht über andere Kanäle zugegriffen werden kann, wodurch die Sicherheit von i geschützt wird.
Eine Variable im Speicher beibehalten. Wie im vorherigen Beispiel existiert ich aufgrund des Verschlusses immer im Speicher das i in der Funktion existiert. Jedes Mal, wenn RS () ausgeführt wird, werde ich hinzugefügt 1.