Der Mechanismus der Bereichsverkettung in JavaScript kann einige Nebenwirkungen haben: Ein Abschluss kann nur den letzten Wert einer Variablen in der enthaltenden Funktion erhalten. Bei der Verwendung von Abschlüssen müssen wir auf den Variablenwert achten, da hier häufig Fehler passieren.
Im Folgenden verwenden wir ein sehr extremes Beispiel, um dieses Problem zu veranschaulichen. In der tatsächlichen Entwicklung schreiben wir im Allgemeinen keinen solchen Code. Der Code für dieses Beispiel lautet wie folgt:
function fn1(){ var arr = new Array(); //变量i保存在fn1作用域中 for(var i = 0; i < 10;i++){ arr[i] = function(){ return i; } } return arr; } var values = fn1(); for(var i = 0; i < values.length;i++){ //此时通过闭包来调用所有的函数,当输出i的时候会到上一级的作用域中查找,此时i的值是10,所以输出的都是10 document.write(values[i]()+"<br>"); }
Beim Ausführen des obigen Codes gehen wir davon aus, dass 0-9 auf der Seite gedruckt werden, tatsächlich werden jedoch 10 10er gedruckt. Lassen Sie uns diesen Code analysieren: Im Implementierungscode wird eine Funktion fn1 erstellt, in der Funktion wird ein Array-Objekt erstellt und dem Array wird über eine for-Schleife ein Wert zugewiesen. Die Schleife wird zehnmal wiederholt und jedes Mal wird eine anonyme Funktion ausgeführt wird in das Array eingefüllt, gibt einen Wert zurück und gibt schließlich ein Array-Objekt zurück. Rufen Sie dann den Verweis auf die Funktion fn1 ab und geben Sie dann die Werte im Array auf der Seite über eine Schleife aus.
Das Scope-Chain-Speichermodell des obigen Programms ist in der folgenden Abbildung dargestellt:
Aus der Abbildung können wir das jedes Mal in der Funktion fn1 ersehen Schleifen generieren eine anonyme Funktion und haben ihre eigenen Bereichsketten. Die hohen Bits ihrer Bereichsketten verweisen auf den globalen Bereich, die mittleren Bits verweisen auf den äußeren fn1-Bereich und die niedrigen Bits verweisen auf ihren eigenen Bereich.
Nachdem die Funktion fn1 ausgeführt wurde, beträgt der Wert des Attributs i im Bereich von fn1 10. Zu diesem Zeitpunkt beginnt der GC mit der Wiederverwendung von fn1, stellt jedoch fest, dass es eine anonyme Funktion gibt, die auf den Bereich verweist von fn1, daher wird der Umfang von fn1 nicht recycelt.
Wenn die anonyme Funktion ausgeführt wird, sucht sie in ihrem eigenen Bereich nach dem Attribut i, findet es jedoch nicht und geht daher zu ihrem übergeordneten fn1-Bereich, um es zu finden. Zu diesem Zeitpunkt ist der i-Wert in Der fn1-Bereich ist 10, sodass alle anonymen Funktionen denselben i-Wert erhalten: 10.
Die Möglichkeit, dieses Problem zu lösen, besteht darin, eine anonyme Funktion in der anonymen Funktion zurückzugeben und den aktuellen Wert über eine Variable zu speichern. Der Code lautet wie folgt:
function fn1(){ var arr = new Array(); for(var i = 0; i < 10;i++){ arr[i] = function(num){ return function(){ return num; } }(i); } return arr; } var values = fn1(); for(var i = 0; i < values.length;i++){ //每一个fs都是在不同的作用域链中,num也是保存在不同的作用域中,所以输出0-9 document.write(values[i]()+"<br>"); }
Zu diesem Zeitpunkt wird der Wert von num im Bereich jeder anonymen Funktion gespeichert und der Wert entspricht genau dem Indexwert jeder Schleife. Auf diese Weise findet die anonyme Funktion jedes Mal, wenn sie aufgerufen wird, das num-Attribut in ihrem eigenen Bereich, und die Werte dieser num sind unterschiedlich. Gleichzeitig wird nicht nach dem i-Attribut gesucht der Funktionsumfang von fn1.
Der obige Code generiert den Umfang von 20 anonymen Funktionen. Wenn es sich bei dem Code nicht um einen einfachen Rückgabewert, sondern um einige komplexere Vorgänge handelt, belegt er viel Speicherplatz.
Dieses Objekt im Abschluss
Die Verwendung dieses Objekts im Abschluss führt ebenfalls zu unerwarteten Problemen. Dieses Objekt wird zur Laufzeit basierend auf der Ausführungsumgebung der Funktion gebunden: Bei globalen Funktionen ist dieses Objekt das Fenster, und wenn die Funktion als Methode eines Objekts aufgerufen wird, ist dies dieses Objekt. In anonymen Funktionen zeigt dieses Objekt normalerweise auf das Fenster. Schauen wir uns das folgende Beispiel an:
var name = "window"; var person = { name : "Leon", age:22, say:function(){ return function(){ return this.name; } } } console.info(person.say()()); //控制台输出:window
Wenn wir im obigen Code die say()-Methode des Personenobjekts aufrufen, wird nicht der Name des Personenobjekts, sondern der globale Name gedruckt "Fenster". Nachdem person.say() abgeschlossen ist, ist der Funktionsaufruf abgeschlossen. Bevor der Funktionsaufruf endet, zeigt dies auf person, aber wenn die anonyme Funktion aufgerufen wird, zeigt dies auf window, sodass das Ergebnis „window“ ist.
Die Möglichkeit, dieses Problem zu lösen, besteht darin, diese Referenz einer temporären Variablen in der Methode say() zuzuweisen. Der Code lautet wie folgt:
var name = "window"; var person = { name : "Leon", age:22, say:function(){ var that = this; return function(){ return that.name; } } } console.info(person.say()()); //控制台输出:Leon
Das Obige ist der JavaScript-Abschluss – die Variablen im Abschluss und der Inhalt dieses Objekts. Weitere verwandte Inhalte finden Sie auf der chinesischen PHP-Website (www. php.cn)!