Wieder auffüllen:
Verschluss ist eine Schwierigkeit in der JavaScript -Sprache und ihrer Funktion. Viele fortgeschrittene Anwendungen stützen sich auf Schließungen, um die Implementierung zu implementieren.
Verschlussfunktionen
Schließungen haben drei Eigenschaften:
1. Funktion verschachtelte Funktionen
2. Die Funktion kann sich auf externe Parameter und Variablen im Inneren beziehen
3.. Parameter und Variablen werden nicht vom Müllsammlermechanismus erfasst
Definition des Verschlusses und deren Vor- und Nachteile
Schließungen beziehen sich auf Funktionen, die Zugriff auf Variablen im Bereich einer anderen Funktion haben. Der häufigste Weg, um Schließungen zu erstellen, besteht darin, eine andere Funktion innerhalb einer Funktion zu erstellen und über eine andere Funktion auf lokale Variablen dieser Funktion zuzugreifen.
Der Nachteil von Verschlüssen besteht darin, dass sie ansässiger Speicher sind, der die Speicherverwendung erhöht, und eine unsachgemäße Verwendung kann leicht zu Speicherleckagen führen.
Schließungen sind ein Hauptmerkmal der JavaScript -Sprache. Die Hauptanwendung von Schließungen dient hauptsächlich für: Entwerfen privater Methoden und Variablen.
Nach der Ausführung der allgemeinen Funktion wird das lokale aktive Objekt zerstört und nur der globale Bereich wird im Speicher gespeichert. Aber die Schließsituation ist anders!
Um über das Thema zu sprechen
1. Definition des Verschlusses?
Schauen wir uns einige Definitionen zu Schließungen an:
1. Verschluss bezieht sich auf eine Funktion, die die Erlaubnis hat, in einem anderen Funktionsbereich auf Variablen zuzugreifen.
2. Funktionsobjekte können durch Zielfernrohrketten und Variablen innerhalb des Funktionskörpers im Bereich der Funktion gespeichert werden. Diese Eigenschaft heißt "Verschluss".
3. Interne Funktionen können auf Parameter und Variablen externer Funktionen zugreifen, die sie definieren (außer diesem und Argumenten).
Wenn Sie das Konzept der JS-Schließung systematisch lernen möchten, können Sie sich auf die JS E-Book-Spalte von Wulin.com finden, um zu lernen.
Fassen wir die Definition zusammen
1. Sie können auf Funktionen von Variablen im externen Funktionsbereich zugreifen
2. Die Variablen externer Funktionen, auf die interne Funktionen zugegriffen werden, können im Rahmen der externen Funktion gespeichert werden, ohne recycelt zu werden-dies ist der Kern. Später, wenn wir Schließungen begegnen, sollten wir daran denken. Wir sollten uns auf die Variable konzentrieren, auf die der Verschluss verwiesen wird.
Erstellen Sie eine einfache Schließung
var sayname = function () {var name = 'jozo'; return function () {alert (name);}}; var say = sayname (); sagen();Lassen Sie uns die nächsten beiden Sätze interpretieren:
• Var sagt = SayName (): Gibt eine in der Variablensprechung gespeicherte anonyme interne Funktion zurück und bezieht sich auf den variablen Namen der externen Funktion. Aufgrund des Müllsammlungsmechanismus wird nach Ausführung der SayName -Funktion der variable Name nicht zerstört.
• Say (): Führen Sie die zurückgegebene interne Funktion aus und greifen Sie dennoch auf den variablen Namen und die Ausgabe "Jozo" zu.
2. Bereichskette im Abschluss
Das Verständnis von Bereichsketten ist auch hilfreich, um Schließungen zu verstehen.
Die Suchmethoden von Variablen im Umfang sollten sehr vertraut sein, aber dies ist das, was entlang der Bereichskette nach oben sucht.
Wenn die Funktion aufgerufen wird:
1. Erstellen Sie zuerst einen Ausführungskontext und die entsprechende Bereichskette;
2. Fügen Sie dem aktiven Objekt der Funktion Argumente und andere benannte Parameterwerte hinzu (Aktivierungsobjekt)
SCOPE -Kette: Das aktive Objekt der Stromfunktion hat die höchste Priorität, gefolgt vom aktiven Objekt der externen Funktion, und das aktive Objekt der externen Funktion der externen Funktion nimmt die Sequenz bis zum Ende der Bereichskette ab - dem globalen Bereich. Priorität ist die Reihenfolge der variablen Suche;
Schauen wir uns zunächst eine normale Zielfernrohrkette an:
Funktion Sayname (Name) {return name;} var sagt = sayname ('jozo');Dieser Code enthält zwei Bereiche: a. globaler Umfang; B.SayName -Funktionsbereich, dh es gibt nur zwei variable Objekte. Wenn das variable Objekt in die entsprechende Ausführungsumgebung ausgeführt wird, wird es zu einem aktiven Objekt und wird an das vordere Ende der Bereichskette der Ausführungsumgebung gedrückt, dh es wird die höchste Priorität. Sprechen Sie mit dem Bild:
Dieses Bild ist auch in JS Advanced Programming Books erhältlich, und ich habe alles neu gezeichnet.
Beim Erstellen der Funktion SayName () wird eine Bereichskette, die das variable Objekt im Voraus enthält, die nach 1 in der Abbildung indizierte Bereichskette erstellt und im internen [[Scope]] -Treizattribut gespeichert. Wenn die Funktion sayname () aufgerufen wird, wird eine Ausführungsumgebung erstellt, und dann wird die Bereichskette erstellt, indem das Objekt im Attribut der Funktion [[Scope]] kopiert wird. Danach wird ein anderes aktives Objekt (in der Abbildung in indiziert durch 0 indiziert) erstellt und in das vordere Ende der Umgebung der Ausführungsumgebung gedrückt.
Im Allgemeinen wird das lokale aktive Objekt beim Ausführen der Funktion zerstört und nur der globale Bereich wird im Speicher gespeichert. Die Situation der Schließungen ist jedoch anders:
Werfen wir einen Blick auf die Umfangskette von Schließungen:
Funktion Sayname (name) {return function () {return name;}} var sagt = sayname ('jozo');Diese Verschlussinstanz hat einen weiteren Bereich für die anonyme Funktion als das vorherige Beispiel:
Nachdem die anonyme Funktion aus der Funktion sayname () zurückgegeben wurde, wird seine Bereichskette in ein aktives Objekt und ein globales variables Objekt initialisiert, das die Funktion sayname () enthält. Auf diese Weise kann die anonyme Funktion auf alle in SayName () definierten Variablen und Parameter zugreifen. Noch wichtiger ist, dass sein aktives Objekt nach der Ausführung der Funktion SayName () nicht zerstört wird, da sich die Bereichskette der anonymen Funktion immer noch auf das aktive Objekt bezieht. Mit anderen Worten, nach der Ausführung der Funktion SayName () wird die Bereichskette ihrer Ausführungsumgebung zerstört, aber sein aktives Objekt wird in Erinnerung bleiben, da die anonyme Funktion zerstört wird. Dies ist auch das Problem des Speicherlecks, das später besprochen wird.
Ich schreibe nicht so viel über Themenkettenprobleme und das Schreiben von Dingen in das Buch ist auch sehr anstrengend O (□) o
3. Beispiel für die Schließung
Beispiel 1: Implementierung der Akkumulation
// Methode 1Var a = 0; var add = function () {a ++; console.log (a)} add (); add (); // Methode 2: closeur var add = (function () {var a = 0; return function () {a ++; console.log (a);}}) (); console.log (a); // undefinedAdd (); add ();Im Vergleich dazu ist Methode 2 eleganter und reduziert auch globale Variablen und privatisiert Variablen.
Beispiel 2: Klicken Sie zu jedem Li -Ereignis hinzufügen
var oli = document.getElementsByTagName ('li'); var i; für (i = 0; i <5; i ++) {oli [i] .onclick = function () {alert (i);}} console.log (i); // 5 // anonyme Funktion ausführen (function () {alert (i); // 5} ());Das obige ist ein klassisches Beispiel. Wir alle wissen, dass das Ausführungsergebnis lautet, dass 5 auftauchen, und wir wissen auch, dass Schließungen verwendet werden können, um dieses Problem zu lösen, aber zu Beginn kann ich immer noch nicht verstehen, warum 5 auftauchen und warum Schließungen dieses Problem lösen können. Später sortierte ich es aus und machte klar:
A. Lassen Sie uns zunächst die Situation analysieren, bevor der Verschluss verwendet wird: In der für Schleife binden wir eine anonyme Funktion an jedes Li -Klickereignis, und der Wert der Variablen I gibt in der anonymen Funktion zurück. Wenn die Schleife endet, wird der Wert der Variablen I 5. Zu diesem Zeitpunkt klicken wir auf jedes Li, dh die entsprechende anonyme Funktion (siehe Code oben). Dies ist die Variable I, die I bereits 5 ist, daher taucht jeder Klick auf 5. Da jede hier zurückgegebene anonyme Funktion auf dieselbe Variable I bezieht. Wenn wir eine neue Variable erstellen, um den aktuellen I -Wert von i zu speichern, wenn die Schleife ausgeführt wird, lassen Sie die anonyme Funktion diese Variable anwenden und schließlich diese anonyme Funktion zurückgeben, sodass unser Zweck erreicht werden kann. Dies wird mit Schließungen erreicht!
B. Analysieren wir die Situation bei der Verwendung von Schließungen:
var oli = document.getElementsByTagName ('li'); var i; für (i = 0; i <5; i ++) {oli [i] .onclick = (function (num) {var a = num; //, um die Problemrückgabefunktion () {alert (a);}}) (i)} Konsole zu veranschaulichen. // 5Wenn die For -Loop ausgeführt wird, wird die an das Klickereignis gebundene anonyme Funktion i übergeben und sofort ausgeführt, um eine interne anonyme Funktion zurückzugeben. Da die Parameter mit einem Wert übergeben werden, speichert der formale Parameterum den aktuellen Wert von i und weist dann der lokalen Variablen a den Wert zu. Dann hält die interne anonyme Funktion die Referenz von A, dh den aktuellen Wert von i. Nachdem die Schleife ausgeführt wurde, klicken Sie auf jedes Li, und die zurückgegebene anonyme Funktion wird den Wert des gespeicherten a.
4. Anwendung von Schließungen
Schauen wir uns den Zweck der Schließungen an. Durch die Verwendung von Schließungen können wir viele Dinge tun. Simulieren Sie beispielsweise den objektorientierten Codestil. ausdrücken Code eleganter und präzise; und Verbesserung der Code -Ausführungseffizienz in einigen Aspekten.
1. Anonyme Selbstausnahmefunktion
In tatsächlichen Situationen stoßen wir häufig auf eine Situation, in der einige Funktionen nur einmal ausgeführt werden müssen und ihre internen Variablen nicht aufrechterhalten werden müssen, z. B. die UI -Initialisierung, damit wir Schließungen verwenden können:
// Alle Li -Schriftarten in rot ändern (function () {var els = document.getElementsByTagName ('li'); für (var i = 0, lng = elsength; i <lng; i ++) {Els [i] .style.color = 'rot';}}) ();Wir erstellen eine anonyme Funktion und führen sie sofort aus. Da sich das Äußere nicht auf die darin enthaltenen Variablen beziehen kann, werden lokale Variablen wie ELS, I und LNG kurz nach der Ausführung veröffentlicht und Speicher speichern!
Der Schlüssel ist, dass dieser Mechanismus das globale Objekt nicht verschmutzen wird.
2. Implementieren Sie Kapselung/Modularcode
var person = function () {// Der Umfang der Variablen befindet sich in der Funktion, und auf das Var name = "Standard" kann nicht außerhalb zugegriffen werden. return {getName: function () {return name; }, setName: function (newname) {name = newName; }}} (); console.log (Person.Name); // Direktzugriff ist das Ergebnis undefined Console.log (person.getName ()); // Standard Person.setName ("Jozo"); console.log (person.getName ()); // Jozo3.. Implementieren Sie objektorientiert
Auf diese Weise haben verschiedene Objekte (Klassenanfälle) unabhängige Mitglieder und Staaten und stören sich nicht gegenseitig. Obwohl es in JavaScript keinen solchen Mechanismus als Klasse gibt, können wir durch Verschluss solche Mechanismen simulieren. Sprechen wir über das obige Beispiel:
Funktion person () {var name = "Standard"; return {getName: function () {return name; }, setName: function (newname) {name = newName; }}}; var person1 = person (); print (person1.getName ()); John.SetName ("Person1"); print (person1.getName ()); // Person1 var person2 = person (); print (person2.getName ()); Jack.SetName ("erson2"); print (erson2.getName ()); // Person2Die zwei Instanzen der Person Person1 und Person2 stören sich nicht miteinander! Weil diese beiden Instanzen einen unabhängigen Zugriff auf das Namensmitglied haben.
5. Speicherlecks und Lösungen
Müllrecyclingmechanismus
Apropos Gedächtnismanagement, ist von der Müllsammlung von Müll in JS von Natur aus untrennbar miteinander verbunden. Es gibt zwei Strategien, um die Müllsammlung zu realisieren: Markierung und Referenzzählung ;
MARK -Entfernung: Wenn der Müllsammler ausgeführt wird, markiert er alle im Speicher gespeicherten Variablen. Anschließend werden die Tags von Variablen in der Umgebung und die Tags von Variablen, auf die Variablen in der Umgebung verwiesen, entfernt. Wenn die Variable danach erneut markiert ist, bedeutet dies, dass die Variable gelöscht werden kann. Bis 2008 haben IE, Firefox, Opera, Chrome und Safari JavaScript diese Methode verwendet.
Referenzzahl: Verfolgen Sie die Häufigkeit, mit der auf jeden Wert verwiesen wird. Wenn eine Variable deklariert wird und der Variablen ein Wert eines Referenztyps zugewiesen wird, beträgt die Anzahl der Referenzen, die dieser Wert verwiesen.
Ein großes Problem mit dieser Methode ist eine zirkuläre Referenz, dh Objekt A enthält einen Zeiger auf B, und Objekt B enthält auch eine Referenz auf A. Dies kann dazu führen, dass eine große Menge an Gedächtnis recycelt wird (Speicherlecks), da ihre Referenzen niemals 0 sein können. In den frühen IE-Versionen (IE4-IE6) adoptiert ein Gründungs-Sammelmechanismus, der bewertet wurde. Einer der Gründe, warum Verschlüsse verursachten, war ein Fehler in diesem Algorithmus.
Wir wissen, dass einige Objekte im IE keine nativen JavaScript -Objekte sind. Beispielsweise werden Objekte in BOM und DOM in Form von COM -Objekten implementiert, und der Müllansammlungsmechanismus von COM -Objekten nimmt die Referenzzählung an. Obwohl die JavaScript -Engine von IE eine Tag -Clearing -Strategie anwendet, basiert der Zugriff auf COM -Objekte immer noch auf der Referenzzählung. Solange COM -Objekte in IE gestaltet sind, wird es ein Problem der kreisförmigen Referenzen geben!
Nehmen Sie eine Kastanie:
window.onload = function () {var el = document.getElementById ("id"); el.onclick = function () {alert (el.id);}}Warum verursacht dieser Code Speicherlecks?
el.onclick = function () {alert (el.id);};Bei der Ausführung dieses Code wird das anonyme Funktionsobjekt dem Onclick -Attribut von EL zugewiesen. Dann bezieht sich die anonyme Funktion auf das El -Objekt im Inneren, und es gibt eine kreisförmige Referenz, sodass sie nicht recycelt werden kann.
Lösung:
window.onload = function () {var el = document.getElementById ("id"); var id = el.id; // Unreference el.onclick = function () {alert (id); } el = null; // Löschen Sie das aktive Objekt in der externen Funktion, auf die der Verschluss verwiesen wird}Die oben genannte Zusammenfassung des relevanten Wissens über JS -Verschlussbereichsbereichsketten -Müllabfuhr -Speicher -Leck, das Ihnen vom Herausgeber vorgestellt wurde. Ich hoffe, es wird für alle hilfreich sein!