for
Baseline
Weitgehend verfügbar
Diese Funktion ist gut etabliert und funktioniert auf vielen Geräten und in vielen Browserversionen. Sie ist seit Juli 2015 browserübergreifend verfügbar.
Die for-Anweisung erstellt eine Schleife, die aus drei optionalen Ausdrücken besteht. Diese sind in Klammern eingeschlossen und durch Semikolons getrennt, gefolgt von einer Anweisung (in der Regel eine Block-Anweisung), die in der Schleife ausgeführt wird.
Probieren Sie es aus
let str = "";
for (let i = 0; i < 9; i++) {
str += i;
}
console.log(str);
// Expected output: "012345678"
Syntax
for (initialization; condition; afterthought)
statement
initializationOptional-
Ein Ausdruck (einschließlich Zuweisungsausdrücken) oder eine Variablendeklaration, die einmal ausgewertet wird, bevor die Schleife beginnt. Typischerweise zum Initialisieren einer Zählervariablen verwendet. Dieser Ausdruck kann optional neue Variablen mit den Schlüsselwörtern
varoderletdeklarieren. Variablen, die mitvardeklariert wurden, sind nicht lokal zur Schleife, d.h. sie befinden sich im gleichen Gültigkeitsbereich wie diefor-Schleife. Variablen, die mitletdeklariert wurden, sind lokal zur Anweisung.Das Ergebnis dieses Ausdrucks wird verworfen.
conditionOptional-
Ein Ausdruck, der vor jeder Schleifeniteration ausgewertet wird. Wenn dieser Ausdruck zu true ausgewertet wird, wird
statementausgeführt. Wenn der Ausdruck zu false ausgewertet wird, wird die Schleife verlassen und die Ausführung geht zur ersten Anweisung nach demfor-Konstrukt.Dieser Konditionaltest ist optional. Wenn weggelassen, wird die Bedingung immer zu true ausgewertet.
afterthoughtOptional-
Ein Ausdruck, der am Ende jeder Schleifeniteration ausgewertet wird. Dies geschieht vor der nächsten Auswertung von
condition. Allgemein verwendet, um die Zählervariable zu aktualisieren oder zu inkrementieren. statement-
Eine Anweisung, die ausgeführt wird, solange die Bedingung zu true ausgewertet wird. Sie können eine Block-Anweisung verwenden, um mehrere Anweisungen auszuführen. Um keine Anweisung innerhalb der Schleife auszuführen, verwenden Sie eine leere Anweisung (
;).
Beschreibung
Wie andere Schleifen-Anweisungen können in statement Steuerflussanweisungen verwendet werden:
Beispiele
>Verwendung von for
Die folgende for-Anweisung beginnt mit der Deklaration der Variablen i und deren Initialisierung auf 0. Sie überprüft, ob i kleiner als neun ist, führt die beiden nachfolgenden Anweisungen aus und erhöht i nach jedem Durchlauf der Schleife um 1.
for (let i = 0; i < 9; i++) {
console.log(i);
// more statements
}
Initialisierungsblock-Syntax
Der Initialisierungsblock akzeptiert sowohl Ausdrücke als auch Variablendeklarationen. Allerdings können Ausdrücke den in-Operator nicht unverklammert verwenden, da dies mit einer for...in-Schleife verwechselt werden könnte.
for (let i = "start" in window ? window.start : 0; i < 9; i++) {
console.log(i);
}
// SyntaxError: 'for-in' loop variable declaration may not have an initializer.
// Parenthesize the whole initializer
for (let i = ("start" in window ? window.start : 0); i < 9; i++) {
console.log(i);
}
// Parenthesize the `in` expression
for (let i = ("start" in window) ? window.start : 0; i < 9; i++) {
console.log(i);
}
Optionale for-Ausdrücke
Alle drei Ausdrücke im Kopf der for-Schleife sind optional. Zum Beispiel ist es nicht erforderlich, den initialization-Block zur Initialisierung von Variablen zu verwenden:
let i = 0;
for (; i < 9; i++) {
console.log(i);
// more statements
}
Wie der initialization-Block ist auch der condition-Teil optional. Wenn Sie diesen Ausdruck weglassen, müssen Sie sicherstellen, dass Sie die Schleife im Körper unterbrechen, um keine Endlosschleife zu erstellen.
for (let i = 0; ; i++) {
console.log(i);
if (i > 3) break;
// more statements
}
Sie können auch alle drei Ausdrücke weglassen. Stellen Sie wiederum sicher, dass Sie eine break-Anweisung verwenden, um die Schleife zu beenden und eine Variable zu ändern (erhöhen), sodass die Bedingung für die break-Anweisung irgendwann wahr wird.
let i = 0;
for (;;) {
if (i > 3) break;
console.log(i);
i++;
}
Wenn Sie jedoch nicht alle drei Ausdrücke vollständig verwenden — insbesondere, wenn Sie keine Variablen mit dem ersten Ausdruck deklarieren, sondern etwas im oberen Gültigkeitsbereich ändern — sollten Sie stattdessen eine while-Schleife verwenden, die die Absicht klarer macht.
let i = 0;
while (i <= 3) {
console.log(i);
i++;
}
Lexikalische Deklarationen im Initialisierungsblock
Eine Variable im Initialisierungsblock zu deklarieren, weist wichtige Unterschiede zu einer Deklaration im oberen Gültigkeitsbereich auf, insbesondere wenn innerhalb des Schleifenkörpers eine Closure erstellt wird. Zum Beispiel für den folgenden Code:
for (let i = 0; i < 3; i++) {
setTimeout(() => {
console.log(i);
}, 1000);
}
Es protokolliert 0, 1 und 2, wie erwartet. Wenn die Variable jedoch im oberen Gültigkeitsbereich definiert ist:
let i = 0;
for (; i < 3; i++) {
setTimeout(() => {
console.log(i);
}, 1000);
}
Es protokolliert 3, 3 und 3. Der Grund ist, dass jede setTimeout-Funktion eine neue Closure erstellt, die über die i-Variable geschlossen wird, aber wenn i nicht auf den Schleifenkörper beschränkt ist, verweisen alle Closures auf die gleiche Variable, wenn sie schließlich aufgerufen werden — und aufgrund der asynchronen Natur von setTimeout() geschieht dies, nachdem die Schleife bereits beendet ist, was dazu führt, dass der Wert von i in den Körpern aller in die Warteschlange gestellten Rückrufe den Wert 3 hat.
Dies passiert auch, wenn Sie eine var-Anweisung als Initialisierung verwenden, weil Variablen, die mit var deklariert wurden, nur funktionsgebunden, aber nicht lexikalisch gebunden sind (d.h. sie können nicht auf den Schleifenkörper beschränkt werden).
for (var i = 0; i < 3; i++) {
setTimeout(() => {
console.log(i);
}, 1000);
}
// Logs 3, 3, 3
Die Wirkung der Bereichseinschränkung des Initialisierungsblocks kann so verstanden werden, als ob die Deklaration innerhalb des Schleifenkörpers passiert, aber zufällig innerhalb der condition- und afterthought-Teile zugänglich ist. Genauer gesagt sind let-Deklarationen bei for-Schleifen besonders behandelt — wenn initialization eine let-Deklaration ist, dann passiert folgendes jedes Mal, nachdem der Schleifenkörper ausgewertet wurde:
- Ein neuer lexikalischer Gültigkeitsbereich wird mit neuen
let-deklarierte Variablen erstellt. - Die Bindungswerte aus der letzten Iteration werden verwendet, um die neuen Variablen neu zu initialisieren.
afterthoughtwird im neuen Bereich ausgewertet.
Das erneute Zuweisen der neuen Variablen innerhalb von afterthought beeinflusst also nicht die Bindungen aus der vorherigen Iteration.
Ein neuer lexikalischer Bereich wird auch nach initialization erstellt, unmittelbar bevor condition zum ersten Mal ausgewertet wird. Diese Details können durch die Erstellung von Closures beobachtet werden, die es Ihnen ermöglichen, eine Bindung zu einem bestimmten Zeitpunkt zu erfassen. Zum Beispiel in diesem Code wird eine innerhalb des initialization-Abschnitts erstellte Closure nicht durch Neuzuordnungen von i im afterthought-Abschnitt aktualisiert:
for (let i = 0, getI = () => i; i < 3; i++) {
console.log(getI());
}
// Logs 0, 0, 0
Das protokolliert nicht "0, 1, 2", wie es der Fall wäre, wenn getI im Schleifenkörper deklariert wäre. Dies liegt daran, dass getI nicht bei jeder Iteration neu ausgewertet wird — vielmehr wird die Funktion einmal erstellt und schließt über die i-Variable, die die bei der erstmaligen Initialisierung der Schleife deklarierte Variable referenziert. Nachfolgende Updates des Wertes von i erstellen tatsächlich neue Variablen namens i, die getI nicht sieht. Eine Möglichkeit, dies zu beheben, besteht darin, getI jedes Mal neu zu berechnen, wenn i aktualisiert wird:
for (let i = 0, getI = () => i; i < 3; i++, getI = () => i) {
console.log(getI());
}
// Logs 0, 1, 2
Die i-Variable innerhalb der initialization ist von der i-Variable innerhalb jeder Iteration, einschließlich der ersten, unterschiedlich. In diesem Beispiel gibt getI 0 zurück, obwohl der Wert von i innerhalb der Iteration vorher inkrementiert wird:
for (let i = 0, getI = () => i; i < 3;) {
i++;
console.log(getI());
}
// Logs 0, 0, 0
Tatsächlich können Sie diese anfängliche Bindung der i-Variable erfassen und später neu zuweisen, und dieser aktualisierte Wert wird für den Schleifenkörper nicht sichtbar sein, der die nächste neue Bindung von i sieht.
for (
let i = 0, getI = () => i, incrementI = () => i++;
getI() < 3;
incrementI()
) {
console.log(i);
}
// Logs 0, 0, 0
Das protokolliert "0, 0, 0", weil die i-Variable in jeder Schleifenauswertung tatsächlich eine separate Variable ist, aber getI und incrementI lesen und schreiben beide die initiale Bindung von i, nicht das, was anschließend deklariert wurde.
Verwendung von for ohne Körper
Der folgende for-Zyklus berechnet die Offset-Position eines Knotens im afterthought-Abschnitt, und daher ist es nicht erforderlich, den statement-Abschnitt zu verwenden. Ein Semikolon wird stattdessen verwendet.
function showOffsetPos(id) {
let left = 0;
let top = 0;
for (
let itNode = document.getElementById(id); // initialization
itNode; // condition
left += itNode.offsetLeft,
top += itNode.offsetTop,
itNode = itNode.offsetParent // afterthought
); // semicolon
console.log(
`Offset position of "${id}" element:
left: ${left}px;
top: ${top}px;`,
);
}
showOffsetPos("content");
// Logs:
// Offset position of "content" element:
// left: 0px;
// top: 153px;
Beachten Sie, dass das Semikolon nach der for-Anweisung obligatorisch ist, da es als leere Anweisung fungiert. Andernfalls übernimmt die for-Anweisung die folgende console.log-Zeile als ihren statement-Abschnitt, was dazu führt, dass das log mehrmals ausgeführt wird.
Verwendung von for mit zwei iterierenden Variablen
Sie können zwei Zähler erstellen, die mit einem Komma-Operator innerhalb einer for-Schleife gleichzeitig aktualisiert werden. Mehrere let- und var-Deklarationen können auch mit Kommas verbunden werden.
const arr = [1, 2, 3, 4, 5, 6];
for (let l = 0, r = arr.length - 1; l < r; l++, r--) {
console.log(arr[l], arr[r]);
}
// 1 6
// 2 5
// 3 4
Spezifikationen
| Spezifikation |
|---|
| ECMAScript® 2027 Language Specification> # sec-for-statement> |