VorwortClosures und Garbage Collection-Mechanismen sind beim Front-End-Lernen und -Entwickeln oft schwierig, und solche Probleme treten häufig bei Interviews auf. Dieser Artikel zeichnet meine Notizen zu diesem Aspekt während des Studiums und der Arbeit auf. Text 1. AbschlussClosures sind eine Schwierigkeit der Sprache Javascript, aber auch ihr Merkmal. Viele fortgeschrittene Anwendungen sind auf Closures angewiesen. Als JavaScript-Entwickler ist es sehr wichtig, Closures zu verstehen. 1.1 Was sind Verschlüsse?Ein Closure ist eine Funktion, die auf die Variable einer anderen Funktion verweist. Sie wird generiert, wenn die innere Funktion nach außen zurückgegeben und gespeichert wird. (Die Scope-Chain-AO der inneren Funktion verwendet die AO der äußeren Funktion.) Da auf die Variable verwiesen wird, wird sie nicht wiederverwendet und kann daher zum Kapseln einer privaten Variable verwendet werden. Unnötige Schließungen erhöhen jedoch nur den Speicherverbrauch. 1.2 Eigenschaften von Verschlüssen①Funktionsverschachtelungsfunktion ② Die Funktion kann auf Parameter und Variablen außerhalb der Funktion verweisen ③Parameter und Variablen werden vom Garbage Collection-Mechanismus nicht recycelt 1.3 Verschlüsse verstehenBasierend auf dem uns vertrauten Wissen über Bereichsketten betrachten wir nun das Problem der Zähler: Wie implementiert man eine Funktion, die den Zähler bei jedem Aufruf der Funktion um eins erhöht. var Zähler=0; Funktion demo3(){ Konsole.log(Zähler+=1); } demo3();//1 demo3();//2 Var Zähler=5; demo3(); //6 Wenn der Wert des Zählers in der obigen Methode an irgendeiner Stelle geändert wird, wird der Zähler ungültig. JavaScript verwendet Closures, um dieses Problem zu lösen, d. h. Funktionen werden in Funktionen eingebettet. Sehen wir uns an, wie Closures zur Implementierung verwendet werden. Funktion add() { Var-Zähler = 0; Rückgabefunktion plus() { Zähler += 1; Rückgabezähler } } var Anzahl = add() konsole.log(Anzahl()) // 1 var Zähler=100 konsole.log(Anzahl()) // 2 Das Obige ist ein Beispiel für die Verwendung von Closures. Eine Plus-Funktion ist in die Add-Funktion eingebettet und die Zählvariable bezieht sich auf die zurückgegebene Funktion. Jedes Mal, wenn die externe Funktion Add ausgeführt wird, wird ein Stück Speicherplatz freigegeben. Die Adresse der externen Funktion ist anders und es wird eine neue Adresse erstellt. Die Plus-Funktion ist in die Add-Funktion eingebettet und erzeugt so einen lokalen Variablenzähler. Jedes Mal, wenn die Zählfunktion aufgerufen wird, wird der Wert der lokalen Variablen um eins erhöht, wodurch das eigentliche Zählerproblem realisiert wird. 1.4 Wichtigste Umsetzungsformen von VerschlüssenEs gibt hier zwei Hauptformen des Lernens von Closures: ① Funktion als Rückgabewert, der im obigen Beispiel verwendet wird. Funktion showName(){ var name="xiaoming" Rückgabefunktion(){ Rückgabename } } var name1=showName() Konsole.log(Name1()) Ein Abschluss ist eine Funktion, die Variablen aus einer anderen Funktion lesen kann. Ein Abschluss ist eine Brücke, die das Innere einer Funktion mit dem Äußeren der Funktion verbindet. ②Abschluss als Parameter übergeben Variablennummer = 15 var foo = Funktion(x){ wenn(x>num){ console.log(x) } } Funktion foo2(fnc){ Var-Nummer = 30 fnc(25) } foo2(foo) // 25 Im obigen Code wird die Funktion foo als Parameter an die Funktion foo2 übergeben. Wenn foo2 ausgeführt wird, wird 25 als Parameter an foo übergeben. Zu diesem Zeitpunkt ist der Wert von num bei der Beurteilung von x>num die num im Bereich der erstellten Funktion, d. h. die globale num, nicht die num innerhalb von foo2, daher wird 25 ausgegeben. 1.5 Vor- und Nachteile von ClosuresVorteil: ① Schützen Sie die Sicherheit von Variablen innerhalb der Funktion, implementieren Sie eine Kapselung und verhindern Sie, dass Variablen in andere Umgebungen fließen und Namenskonflikte verursachen ② Behalten Sie eine Variable im Speicher für die Zwischenspeicherung bei (übermäßiger Gebrauch ist jedoch auch ein Nachteil, da er Speicher verbraucht). ③Anonyme selbstausführende Funktionen können den Speicherverbrauch reduzieren Mangel: ① Einer der Punkte wurde oben bereits berücksichtigt, nämlich, dass die referenzierten privaten Variablen nicht zerstört werden können, was den Speicherverbrauch erhöht und Speicherlecks verursacht. Die Lösung besteht darin, sie nach Verwendung der Variablen manuell auf Null zuzuweisen. ② Zweitens führt Closures zu Leistungseinbußen, da sie domänenübergreifenden Zugriff beinhalten. Wir können die Auswirkungen auf die Ausführungsgeschwindigkeit verringern, indem wir bereichsübergreifende Variablen in lokalen Variablen speichern und dann direkt auf lokale Variablen zugreifen. 1.6 Verwendung von Verschlüssenfür (var i = 0; i < 5; i++) { setzeTimeout(Funktion() { konsole.log( i); }, 1000); } konsole.log(i); Schauen wir uns die obige Frage an. Dies ist eine sehr häufige Frage, aber was wird die Ausgabe sein? Die meisten Leute wissen, dass das Ausgabeergebnis 5,5,5,5,5,5 ist. Wenn Sie genau hinschauen, werden Sie feststellen, dass diese Frage viele clevere Aspekte hat. Was ist die spezifische Ausgabereihenfolge dieser 6 5er? 5 -> 5,5,5,5,5. Wer sich mit Synchronisation und Asynchronität auskennt, kann diese Situation leicht verstehen. Lassen Sie uns auf der Grundlage der obigen Fragen darüber nachdenken, wie die sequentielle Ausgabe von 5 -> 0,1,2,3,4 erreicht werden kann. für (var i = 0; i < 5; i++) { (Funktion(j) { // j = i setzeTimeout(Funktion() { konsole.log( j); }, 1000); })(ich); } konsole.log( i); //5 -> 0,1,2,3,4 Auf diese Weise wird der For-Schleife eine anonyme Funktion hinzugefügt. Der Eingabeparameter der anonymen Funktion ist jedes Mal der Wert von i. Eine Sekunde nachdem die synchrone Funktion 5 ausgegeben hat, gibt sie weiterhin 01234 aus. für (var i = 0; i < 5; i++) { setzeTimeout(Funktion(j) { konsole.log(j); }, 1000, i); } konsole.log( i); //5 -> 0,1,2,3,4 Wenn Sie sich die setTimeout-API genauer ansehen, werden Sie feststellen, dass sie über einen dritten Parameter verfügt, der das Problem der Übergabe von i über eine anonyme Funktion löst. var Ausgabe = Funktion (i) { setzeTimeout(Funktion() { konsole.log(i); }, 1000); }; für (var i = 0; i < 5; i++) { output(i); // Der hier übergebene i-Wert wird kopiert} konsole.log(i); //5 -> 0,1,2,3,4 Hier wird ein Abschluss verwendet, um den Funktionsausdruck als Parameter an die For-Schleife zu übergeben, wodurch auch der obige Effekt erzielt wird. für (sei i = 0; i < 5; i++) { setzeTimeout(Funktion() { console.log(neues Datum, i); }, 1000); } console.log(neues Datum, i); //5 -> 0,1,2,3,4 Wer den Gültigkeitsbereich des Let-Blocks kennt, wird an die obige Methode denken. Aber was, wenn Sie einen Effekt wie 0 -> 1 -> 2 -> 3 -> 4 -> 5 erzielen möchten? für (var i = 0; i < 5; i++) { (Funktion(j) { setzeTimeout(Funktion() { console.log(neues Datum, j); }, 1000 * j); // Ändern Sie hier die Timerzeit von 0~4 })(i); } setTimeout(function() { // Fügen Sie hier einen Timer hinzu und stellen Sie das Timeout auf 5 Sekunden ein console.log(new Date, i); }, 1000 * i); //0 -> 1 -> 2 -> 3 -> 4 -> 5 Es gibt auch den folgenden Code, der durch Promise implementiert wird. const Aufgaben = []; for (var i = 0; i < 5; i++) { // Die Deklaration von i kann hier nicht in let geändert werden. Was muss ich tun, wenn ich sie ändern möchte? ((j) => { tasks.push(neues Versprechen((auflösen) => { setzeTimeout(() => { console.log(neues Datum, j); resolve(); // Hier muss aufgelöst werden, sonst funktioniert der Code nicht wie erwartet }, 1000 * j); // Das Timeout des Timers wird schrittweise erhöht })); })(ich); } Versprechen.alle(Aufgaben).dann(() => { setzeTimeout(() => { console.log(neues Datum, i); }, 1000); // Beachten Sie, dass wir das Timeout nur auf 1 Sekunde einstellen müssen }); //0 -> 1 -> 2 -> 3 -> 4 -> 5 const tasks = []; // Hier ist das Promise für asynchrone Operationen const Ausgabe = (i) => neues Versprechen((Auflösung) => { setzeTimeout(() => { console.log(neues Datum, i); lösen(); }, 1000 * i); }); // Alle asynchronen Operationen generieren für (var i = 0; i < 5; i++) { Aufgaben.push(Ausgabe(i)); } // Nachdem der asynchrone Vorgang abgeschlossen ist, geben Sie das letzte i aus Versprechen.alle(Aufgaben).dann(() => { setzeTimeout(() => { console.log(neues Datum, i); }, 1000); }); //0 -> 1 -> 2 -> 3 -> 4 -> 5 // Schlaf in anderen Sprachen simulieren, tatsächlich kann es jede asynchrone Operation sein const sleep = (timeoutMS) => new Promise((resolve) => { setTimeout(auflösen, timeoutMS); }); (async () => { // asynchroner Funktionsausdruck, der bei der Deklaration für (var i = 0; i < 5; i++) ausgeführt wird { wenn (i > 0) { warte auf Schlaf (1000); } console.log(neues Datum, i); } warte auf Schlaf (1000); console.log(neues Datum, i); })(); //0 -> 1 -> 2 -> 3 -> 4 -> 5 Im obigen Code werden Closures verwendet. Kurz gesagt, Closures finden den Endwert der entsprechenden Variablen in der übergeordneten Funktion an derselben Adresse. 2. SpeicherbereinigungsmechanismusDie Speicherverwaltung in JavaScript erfolgt automatisch und unsichtbar. Wir erstellen primitive Typen, Objekte, Funktionen … all dies erfordert Speicher. Es gibt zwei häufig verwendete Methoden zur Speicherbereinigung: Mark-Sweep und Referenzzählung. 1. Markieren und Fegen Wenn der Garbage Collector ausgeführt wird, markiert er alle im Speicher gespeicherten Variablen. Anschließend werden die Variablen in der Umgebung und die von den Variablen in der Umgebung referenzierten Token entfernt. Danach markierte Variablen gelten als gelöscht, da auf sie von Variablen in der Umgebung nicht mehr zugegriffen werden kann. endlich. Der Garbage Collector führt die Speicherbereinigung durch, zerstört die markierten Werte und gibt den von ihnen belegten Speicherplatz zurück. 2. Referenzzählung Beim Referenzzählen wird nachverfolgt, wie oft auf jeden Wert verwiesen wird. Wenn eine Variable deklariert und der Variablen ein Referenztyp zugewiesen wird, beträgt der Referenzzähler des Werts 1. Umgekehrt, wenn die Variable, die eine Referenz auf diesen Wert enthält, einen anderen Wert erhält, wird die Anzahl der Referenzen auf diesen Wert um 1 reduziert. Wenn die Anzahl der Zitate 0 wird, Dies bedeutet, dass auf diesen Wert nicht mehr zugegriffen werden kann und der von ihm belegte Speicherplatz zurückgefordert werden kann. Auf diese Weise wird beim nächsten Ausführen des Garbage Collector Dadurch wird der Speicher freigegeben, der von Werten belegt ist, deren Referenzzähler 0 ist. ZusammenfassenDies ist das Ende dieses Artikels über JS-Closures und Garbage Collection-Mechanismen. Weitere relevante Inhalte zu JS-Closures und Garbage Collection finden Sie in früheren Artikeln auf 123WORDPRESS.COM oder in den folgenden verwandten Artikeln. Ich hoffe, dass jeder 123WORDPRESS.COM in Zukunft unterstützen wird! Das könnte Sie auch interessieren:
|
<<: Eine kurze Diskussion über die Berechnungsmethode von key_len in MySQL erklären
Beispiel zur MySQL-Passwortänderung – ausführlich...
Die Hauptunterschiede sind folgende: 1. MySQL ver...
Wenn ein Unternehmen eine automatisierte Docker-B...
Wenn sich die Daten ändern, wird die DOM-Ansicht ...
Inhaltsverzeichnis Vorwort 1. for-Schleife 2. whi...
Inhaltsverzeichnis Überblick 1. Kompositions-API ...
Zweck Kapseln Sie die Karussellkomponente und ver...
1. Betreten Sie den Container docker run [Option]...
In diesem Artikel wird der spezifische Code für J...
Wird MySQLs IN den Index ungültig machen? Gewohnh...
Ich habe bereits einen Artikel über mobile Anpass...
Laden Sie die komprimierte Version von MySQL-5.7....
CSS-Importmethode - Inline Durch das Style-Tag-At...
Vorwort Bei der täglichen Entwicklung oder Wartun...
Code kopieren Der Code lautet wie folgt: <Obje...