Heim  >  Artikel  >  Web-Frontend  >  js umfassendes Verständnis von Abschlüssen (Code im Anhang)

js umfassendes Verständnis von Abschlüssen (Code im Anhang)

亚连
亚连Original
2018-05-19 14:13:561163Durchsuche

In diesem Artikel wird hauptsächlich der Abschluss von js vorgestellt. Jetzt habe ich ihn zusammengestellt und mit Ihnen geteilt.

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

Prinzip der Schließung

1 Der Aufruf durch eine Abschlussfunktion wird nicht sofort wiederverwendet, 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 und speichert die lokalen Variablen in der Funktion (die formalen Parameter der Funktion sind ebenfalls lokale Variablen) zusammen mit den an die Funktion übergebenen Variablen wird 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!

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

Mit diesem Code können wir zwei Dinge entdecken: Erstens wird num auf der ursprünglichen Basis erhöht . 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()

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 darüber sprechen, wann ein Abschluss auf eine Schleifenvariable trifft:

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

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?

原来当闭包遇到循环变量时都是循环结束之后统一保存变量值,拿我们上面的例子来说,i是循环变量,当循环全部结束的时候i正好是i++之后的3,而arr[3]是没有值的,所以为undefined,有人会疑惑:为什么item的值是item2,难道不应该是item3吗?注意,在最后一次循环的时候也就是i = 2的时候,item的值为item2,当i++,i = 3循环条件不满足循环结束,此时的item的值已经定下来了,所以此时的arr[i]为arr[3],而item为item2。这样能理解吗?如果我们将代码改成这样那就说得通了:

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

那么问题来了,如何改正呢?且看代码:

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

我们可以用一个自执行函数将i绑定,这样i的每一个状态都会被存储,答案就和我们预期的一样了。

所以以后在使用闭包的时候遇到循环变量我们要习惯性的想到用自执行函数来绑定它。

上面是我整理给大家的,希望今后会对大家有帮助。

相关文章:

js 闭包常见的两种情况的解析

浅谈js 闭包引起的内存泄露问题_javascript技巧

让你分分钟学会 JS 闭包

Das obige ist der detaillierte Inhalt vonjs umfassendes Verständnis von Abschlüssen (Code im Anhang). Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
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