Lassen Sie mich meine Frage klären. Ich frage nicht, wie man den folgenden Code funktioniert. Mir ist bewusst, dass Sie das Schlüsselwort let oder ein iffe verwenden können, das seinen eigenen Wert von i
erfasst. Ich brauche nur Klarheit darüber, wie auf den Wert i
im folgenden Code zugegriffen wird. Ich lese den folgenden Blogpost darüber, wie es ist, dass der folgende Code nicht funktioniert. Blogpost
Der Verfasser behauptet, dass der Code nicht funktioniert, weil wir die Variable i
als Referenz anstelle eines Wertes übergeben. Das heißt, anstatt den Wert von i
pro Iteration anzugeben, stellen wir die Variable dem Callback in setTimeout
als Referenz zur Verfügung. In der Tat, wenn die Schleife beendet und Rückrufe ausgelöst werden, haben wir einen Verweis auf die Variable i
, die 6 sein wird. So funktioniert es?
Hier ist mein Verständnis. Mein Verständnis ist, dass wir nichts an die Callbacks der Funktion setTimeout
weitergeben, wenn die Schleife ausgeführt wird. Wir richten lediglich die asynchronen Aufrufe ein. Wenn die Closure-Callback-Funktionen ausgeführt werden, suchen sie auf der Grundlage der lexikalischen Scoping-Regeln nach der Variablen i
. Das heißt, die Closures sehen in dem Bereich aus, in dem die Callbacks geschlossen haben, was wiederum in diesem Fall 6 wäre, da es abgeschlossen ist, nachdem die for
-Schleife abgeschlossen ist.
Welches ist es, löst die Funktion den Wert von i
auf 6 basierend auf der Variablen, die als Referenz bei jeder Iteration übergeben wird, oder aufgrund von lexikalischem Scoping?
Sie haben Recht, dass das lexikalische Scoping die Ursache für dieses Verhalten ist. Wenn die Timer-Funktionen ausgeführt werden, versuchen sie, i
aufzulösen, und sie müssen den Scope-Kette um es zu finden. Aufgrund von lexikalischem Scoping ist i
nur einmal in der Scope-Kette vorhanden (ein Bereich höher als die Timer-Funktionen), und zu diesem Zeitpunkt ist i
6
, weil die Schleife an diesem Punkt beendet wurde.
Das Schlüsselwort var
bewirkt, dass Variablen in JavaScript entweder einen Funktions- oder einen globalen Bereich haben (abhängig davon, wo diese Deklaration ist). In Ihrem Code bewirkt var i
, dass die Variable i
global existiert (weil sich Ihr Code nicht in einer Funktion befindet) und jede Timer-Funktion dieselbe einzelne i
auflösen muss, wenn sie schließlich ausgeführt wird. Da die Timer-Funktionen nicht ausgeführt werden, bis die Schleife beendet ist, hat i
den letzten Wert (6), den die Schleife verursacht hat.
Ändern Sie var i
in let i
, um einen Blockbereich zu erstellen für i
, um das Problem zu lösen.
let
erstellt einen Blockbereich für die Variable. Bei jeder Iteration der Schleife geben Sie den Schleifenblock erneut ein, und für i
wird ein separater Bereich erstellt, den jede Zeitgeberfunktion zu sich selbst führt.
Lassen Sie mich mit Ihrem Code erklären:
%Vor% Im Moment, als die Funktion setTimeout()
ausgelöst wurde, wird die Variable von i gleich 1,2,3,4,5 sein wie erwartet, bis der Wert von i auf 6 und steigt Stoppen Sie das For-Looping.
Nach einer gewissen Zeit wird der Rückruf von timeout
ausgelöst und loggt log Wert von i . Schau mal oben, wie gesagt, der Wert von i war schon 6.
Die Ursache ist das Fehlen von ECMAScript 5: block scope
. (var i = 1;i <=5 ;i++)
erstellt eine Variable, die in der gesamten Funktion vorhanden ist, und kann von der Funktion im lokalen Bereich oder im Abschlussbereich geändert werden. Aus diesem Grund haben wir in ECMAScript 6 let
.
Es kann leicht behoben werden, indem var
in let
geändert wird:
Tags und Links javascript settimeout