Heim > Web-Frontend > js-Tutorial > Hauptteil

Vertiefendes Verständnis von Abschlüssen beim JS-Lernen

高洛峰
Freigeben: 2016-12-06 11:21:16
Original
947 Leute haben es durchsucht

Der Abschluss ist in js ein relativ schwer zu verstehender Punkt, insbesondere für Leute ohne Programmierkenntnisse.

Tatsächlich gibt es bei Schließungen nur ein paar Dinge, auf die man achten sollte. Wenn man sie alle versteht, ist es nicht schwer, sie zu meistern. Lassen Sie uns über einige Grundprinzipien von Schließungen sprechen.

Das Konzept des Abschlusses

Ein Abschluss ist eine Kombination aus einer Funktion und dem Gültigkeitsbereichsobjekt in der erstellten Funktion. (Bereichsobjekte werden weiter unten besprochen)

Um es einfacher auszudrücken: „Solange eine oder mehrere Funktionen in einer Funktion verschachtelt sind, können wir sie als Abschluss bezeichnen.“

Ähnlich wie dies:

function A() {
 var i = 5;
 return function() {
  console.log('i = '+i);
 }
}
 
var a = A();
a(); // i = 5
Nach dem Login kopieren

Prinzip der Schließung

1 Wenn die lokale Variable der externen Funktion von der Schließungsfunktion aufgerufen wird, ist es wird nicht Es wird sofort recycelt, nachdem die externe Funktion die Ausführung abgeschlossen hat.

Wir wissen, dass das Betriebssystem unabhängig von der Sprache über einen Garbage-Collection-Mechanismus verfügt, um überschüssigen zugewiesenen Speicherplatz zu recyceln und so den Speicher zu reduzieren. Der Lebenszyklus einer Funktion beginnt mit dem Aufruf. Wenn der Funktionsaufruf abgeschlossen ist, werden die lokalen Variablen innerhalb der Funktion durch den Recyclingmechanismus recycelt.

Nehmen wir das obige Beispiel als Beispiel. Wenn unsere externe Funktion A aufgerufen wird, wird die lokale Variable i in A vom Betriebssystem recycelt und existiert nicht Das Ergebnis wird sein. Das ist nicht mehr der Fall, ich werde nicht recycelt. Stellen Sie sich vor, wenn ich recycelt würde, würde die zurückgegebene Funktion dann nicht undefiniert ausgeben?

Warum wurde ich nicht recycelt?

Wenn JavaScript eine Funktion ausführt, erstellt es ein Bereichsobjekt, speichert die lokalen Variablen in der Funktion (die formalen Parameter der Funktion sind ebenfalls lokale Variablen) und wird zusammen mit den an die Funktion übergebenen Variablen initialisiert .

Wenn also A aufgerufen wird, wird ein Gültigkeitsbereichsobjekt erstellt. Nennen wir es Aa. Dann sollte dieses Aa wie folgt aussehen: Aa { i: 5 }; Nachdem die A-Funktion eine Funktion zurückgegeben hat, wird A ausgeführt . Das Aa-Objekt hätte recycelt werden sollen, aber da die zurückgegebene Funktion das Attribut i von Aa verwendet, speichert die zurückgegebene Funktion einen Verweis auf Aa, sodass Aa nicht recycelt wird.

Wenn Sie also das Bereichsobjekt verstehen, können Sie verstehen, warum die lokalen Variablen der Funktion nicht sofort wiederverwendet werden, wenn der Funktionsaufruf abgeschlossen ist, wenn ein Abschluss auftritt.

Ein weiteres Beispiel:

function A(age) {
 var name = 'wind';
 var sayHello = function() {
  console.log('hello, '+name+', you are '+age+' years old!');
 };
 return sayHello;
}
var wind = A(20);
wind(); // hello, wind, you are 20 years old!
Nach dem Login kopieren

Können Sie sagen, was das Scope-Objekt Ww ist?

Ww{ Alter: 20; Name: 'Wind';

2. Bei jedem Aufruf einer externen Funktion wird ein neuer Abschluss generiert gegenseitigen Einfluss.

3. Derselbe Abschluss behält den letzten Zustand bei und basiert beim erneuten Aufruf auf dem letzten Zeitpunkt.

Das Gültigkeitsbereichsobjekt, das bei jedem Aufruf der externen Funktion generiert wird, ist so. Im obigen Beispiel ist das von Ihnen übergebene Parameteralter jedes Mal unterschiedlich, sodass das generierte Objekt unterschiedlich ist jedesmal.

Jedes Mal, wenn eine externe Funktion aufgerufen wird, wird ein neues Scope-Objekt generiert.

function A() {
 var num = 42;
 return function() { console.log(num++); }
}
var a = A();
a(); // 42
a(); // 43
 
var b = A(); // 重新调用A(),形成新闭包
b(); // 42
Nach dem Login kopieren

Mit diesem Code können wir zwei Dinge entdecken: Erstens ändert sich num automatisch basierend auf den ursprünglichen Wert addieren. Dies bedeutet, dass derselbe Abschluss den letzten Status beibehält und beim erneuten Aufruf auf dem letzten Zeitpunkt basiert. 2. Das Ergebnis unseres b(); ist 42, was darauf hinweist, dass es sich um einen neuen Abschluss handelt und nicht von anderen Abschlüssen beeinflusst wird.

Wir können es uns so vorstellen, als würden wir eine Seifenblase blasen. Jedes Mal, wenn ich sie blase (Aufruf einer externen Funktion), wird eine neue Seifenblase (Verschluss) erzeugt Gleichzeitig beeinflussen sich die beiden Seifenblasen nicht gegenseitig.

4. Mehrere in externen Funktionen vorhandene Funktionen „leben und sterben zusammen“

Die folgenden drei Funktionen werden gleichzeitig deklariert und können alle Operationen an den Eigenschaften (lokalen Variablen) ausführen Bereichsobjekt Zugriff und Operationen.

var fun1, fun2, fun3;
function A() {
 var num = 42;
 fun1 = function() { console.log(num); }
 fun2 = function() { num++; }
 fun3 = function() { num--; }
}
 
A();
fun1();  // 42
fun2();
fun2();
fun1();  // 44
fun3();
fun1();  //43
 
var old = fun1;
 
A();
fun1();  // 42
old();  // 43  上一个闭包的fun1()
Nach dem Login kopieren

Da Funktionen nicht mehrere Rückgabewerte haben können, habe ich globale Variablen verwendet. Auch hier können wir sehen, dass beim zweiten Aufruf von A() ein neuer Abschluss erstellt wird.

Wenn ein Abschluss auf eine Schleifenvariable trifft

Wenn wir über Abschlüsse sprechen, müssen wir über die Situation sprechen, wenn ein Abschluss auf eine Schleifenvariable trifft. Schauen Sie sich den folgenden Code an:

function buildArr(arr) {
  var result = [];
  for (var i = 0; i < arr.length; i++) {
    var item = &#39;item&#39; + i;
    result.push( function() {console.log(item + &#39; &#39; + arr[i])} );
  }
  return result;
}
 
var fnlist = buildArr([1,2,3]);
fnlist[0](); // item2 undefined
fnlist[1](); // item2 undefined
fnlist[2](); // item2 undefined
Nach dem Login kopieren

Wie konnte das passieren? Die drei Ausgaben, die wir uns vorstellen, sollten item0 1, item1 2, item2 3 sein. Warum sind im zurückgegebenen Ergebnisarray drei undefinierte Elemente2 gespeichert?

Es stellt sich heraus, dass, wenn ein Abschluss auf eine Schleifenvariable trifft, der Variablenwert nach dem Ende der Schleife einheitlich gespeichert wird. Nehmen Sie unser Beispiel oben, i ist die Schleifenvariable, und wenn die Schleife endet, ist es zufällig i nach i++ 3. Arr[3] hat keinen Wert, daher ist es undefiniert. Manche Leute fragen sich vielleicht: Warum sollte es nicht item3 sein? Beachten Sie, dass in der letzten Schleife, d. h. wenn i = 2, der Wert von item2 ist. Wenn i++, i = 3, sind die Schleifenbedingungen nicht erfüllt und die Schleife endet , also ist arr[i] zu diesem Zeitpunkt arr[3] und item ist item2. Ist das verständlich? Es macht Sinn, wenn wir den Code wie folgt ändern:

function buildArr(arr) {
  var result = [];
  for (var i = 0; i < arr.length; i++) {
    result.push( function() {console.log(&#39;item&#39; + i + &#39; &#39; + arr[i])} );
  }
  return result;
}
 
var fnlist = buildArr([1,2,3]);
fnlist[1](); // item3 undefined
Nach dem Login kopieren

Die Frage ist also, wie kann man das korrigieren? Schauen wir uns den Code an:

function buildArr(arr) {
  var result = [];
  for (var i = 0; i < arr.length; i++) {
    result.push( (function(n) {
      return function() {
       var item = &#39;item&#39; + n;
       console.log(item + &#39; &#39; + arr[n]);
      }
    })(i));
  }
  return result;
}
 
var fnlist = buildArr([1,2,3]);
fnlist[0](); // item0 1
fnlist[1](); // item1 2
fnlist[2](); // item2 3
Nach dem Login kopieren

Wir können eine selbstausführende Funktion verwenden, um i zu binden, sodass jeder Zustand von i gespeichert wird und die Antwort dieselbe ist, wie wir erwartet haben.

Wenn wir also in Zukunft bei der Verwendung von Abschlüssen auf Schleifenvariablen stoßen, müssen wir gewöhnlich daran denken, eine selbstausführende Funktion zu verwenden, um sie zu binden.

Das Obige ist mein Verständnis von Schließungen. Wenn Sie Kommentare oder Vorschläge haben, hoffe ich, dass wir im Kommentarbereich mehr kommunizieren können. Danke und ermutigt euch gegenseitig.


Verwandte Etiketten:
js
Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage