Wir müssen oft Aktionen wiederholen.
Zum Beispiel, Waren nacheinander aus einer Liste auszugeben oder einfach für jede Zahl von 1 bis 10 den gleichen Code auszuführen.
Schleifen sind eine Möglichkeit, denselben Code mehrmals zu wiederholen.
Die for…of- und for…in-Schleifen
Eine kleine Ankündigung für fortgeschrittene Leser.
Dieser Artikel behandelt nur grundlegende Schleifen: while , do..while und for(..;..;..) .
Wenn Sie auf der Suche nach anderen Arten von Schleifen zu diesem Artikel gekommen sind, finden Sie hier die Hinweise:
Siehe for…in, um Objekteigenschaften zu durchlaufen.
Siehe for…of und iterables zum Durchlaufen von Arrays und iterierbaren Objekten.
Ansonsten lesen Sie bitte weiter.
Die while Schleife hat die folgende Syntax:
while (Bedingung) {
// Code
// sogenannter „Loop Body“
} Solange die condition wahr ist, wird der code aus dem Schleifenkörper ausgeführt.
Die folgende Schleife gibt beispielsweise i aus, während i < 3 :
sei i = 0;
while (i < 3) { // zeigt 0, dann 1, dann 2
alarm( i );
i++;
}Eine einzelne Ausführung des Schleifenkörpers wird als Iteration bezeichnet. Die Schleife im obigen Beispiel führt drei Iterationen durch.
Wenn i++ im obigen Beispiel fehlen würde, würde sich die Schleife (theoretisch) für immer wiederholen. In der Praxis bietet der Browser Möglichkeiten, solche Schleifen zu stoppen, und in serverseitigem JavaScript können wir den Prozess abbrechen.
Jeder Ausdruck oder jede Variable kann eine Schleifenbedingung sein, nicht nur Vergleiche: Die Bedingung wird von while ausgewertet und in einen booleschen Wert konvertiert.
Eine kürzere Schreibweise für while (i != 0) ist beispielsweise while (i) :
sei i = 3;
while (i) { // wenn i 0 wird, wird die Bedingung falsch und die Schleife stoppt
alarm( i );
ich--;
}Für einen einzeiligen Körper sind keine geschweiften Klammern erforderlich
Wenn der Schleifenkörper eine einzelne Anweisung enthält, können wir die geschweiften Klammern {…} weglassen:
sei i = 3; while (i) alarm(i--);
Die Bedingungsprüfung kann mithilfe der do..while -Syntax unter den Schleifenkörper verschoben werden:
Tun {
// Schleifenkörper
} while (Bedingung);Die Schleife führt zuerst den Körper aus, überprüft dann die Bedingung und führt sie, solange sie wahr ist, immer wieder aus.
Zum Beispiel:
sei i = 0;
Tun {
alarm( i );
i++;
} while (i < 3); Diese Syntaxform sollte nur verwendet werden, wenn der Schleifenkörper unabhängig davon, ob die Bedingung wahr ist, mindestens einmal ausgeführt werden soll. Normalerweise wird die andere Form bevorzugt: while(…) {…} .
Die for Schleife ist komplexer, aber auch die am häufigsten verwendete Schleife.
Es sieht so aus:
for (Anfang; Bedingung; Schritt) {
// ... Schleifenkörper ...
} Lassen Sie uns die Bedeutung dieser Teile anhand eines Beispiels lernen. Die folgende Schleife führt alert(i) für i von 0 bis (jedoch nicht einschließlich) 3 aus:
for (let i = 0; i < 3; i++) { // zeigt 0, dann 1, dann 2
alarm(i);
} Sehen wir uns die for Anweisung Schritt für Schritt an:
| Teil | ||
|---|---|---|
| beginnen | let i = 0 | Wird beim Eintritt in die Schleife einmal ausgeführt. |
| Zustand | i < 3 | Wird vor jeder Schleifeniteration überprüft. Bei „false“ stoppt die Schleife. |
| Körper | alert(i) | Läuft immer wieder, solange die Bedingung wahr ist. |
| Schritt | i++ | Wird bei jeder Iteration nach dem Text ausgeführt. |
Der allgemeine Schleifenalgorithmus funktioniert folgendermaßen:
Lauf beginnen → (wenn Bedingung → Körper ausführen und Schritt ausführen) → (wenn Bedingung → Körper ausführen und Schritt ausführen) → (wenn Bedingung → Körper ausführen und Schritt ausführen) → ...
Das heißt, begin wird einmal ausgeführt und dann iteriert: Nach jedem condition werden body und step ausgeführt.
Wenn Sie mit Schleifen noch nicht vertraut sind, könnte es hilfreich sein, zum Beispiel zurückzukehren und den Ablauf Schritt für Schritt auf einem Blatt Papier zu reproduzieren.
Genau das passiert in unserem Fall:
// for (let i = 0; i < 3; i++) alarm(i)
// run begin
sei i = 0
// wenn Bedingung → Hauptteil ausführen und Schritt ausführen
if (i < 3) { alarm(i); i++ }
// wenn Bedingung → Hauptteil ausführen und Schritt ausführen
if (i < 3) { alarm(i); i++ }
// wenn Bedingung → Hauptteil ausführen und Schritt ausführen
if (i < 3) { alarm(i); i++ }
// ...fertig, denn jetzt i == 3Inline-Variablendeklaration
Hier wird die „Zähler“-Variable i direkt in der Schleife deklariert. Dies wird als „Inline“-Variablendeklaration bezeichnet. Solche Variablen sind nur innerhalb der Schleife sichtbar.
for (sei i = 0; i < 3; i++) {
alarm(i); // 0, 1, 2
}
alarm(i); // Fehler, keine solche VariableAnstatt eine Variable zu definieren, könnten wir eine vorhandene verwenden:
sei i = 0;
for (i = 0; i < 3; i++) { // eine vorhandene Variable verwenden
alarm(i); // 0, 1, 2
}
alarm(i); // 3, sichtbar, da außerhalb der Schleife deklariert Jeder Teil von for kann übersprungen werden.
Beispielsweise können wir begin weglassen, wenn wir am Schleifenanfang nichts tun müssen.
Wie hier:
sei i = 0; // wir haben es bereits deklariert und zugewiesen
for (; i < 3; i++) { // kein Bedarf für „begin“
alarm( i ); // 0, 1, 2
} Wir können den step auch entfernen:
sei i = 0;
für (; i < 3;) {
alarm( i++ );
} Dadurch ist die Schleife identisch mit while (i < 3) .
Wir können tatsächlich alles entfernen und so eine Endlosschleife erzeugen:
für (;;) {
// wiederholt sich ohne Grenzen
} Bitte beachten Sie, dass die beiden for ; muss vorhanden sein. Andernfalls würde es zu einem Syntaxfehler kommen.
Normalerweise wird eine Schleife beendet, wenn ihre Bedingung falsch wird.
Mit der speziellen break -Direktive können wir den Exit jedoch jederzeit erzwingen.
Die folgende Schleife fragt den Benutzer beispielsweise nach einer Reihe von Zahlen und wird unterbrochen, wenn keine Zahl eingegeben wird:
sei Summe = 0;
while (wahr) {
let value = +prompt("Geben Sie eine Zahl ein", '');
if (!value) break; // (*)
Summe += Wert;
}
Alert( 'Summe: ' + Summe ); Die break -Direktive wird in der Zeile (*) aktiviert, wenn der Benutzer eine leere Zeile eingibt oder die Eingabe abbricht. Es stoppt die Schleife sofort und übergibt die Kontrolle an die erste Zeile nach der Schleife. Nämlich alert .
Die Kombination „Endlosschleife + break nach Bedarf“ eignet sich hervorragend für Situationen, in denen der Zustand einer Schleife nicht am Anfang oder Ende der Schleife, sondern in der Mitte oder sogar an mehreren Stellen ihres Körpers überprüft werden muss.
Die continue Direktive ist eine „leichtere Version“ von break . Es stoppt nicht die ganze Schleife. Stattdessen stoppt es die aktuelle Iteration und zwingt die Schleife, eine neue zu starten (sofern die Bedingung dies zulässt).
Wir können es verwenden, wenn wir mit der aktuellen Iteration fertig sind und mit der nächsten fortfahren möchten.
Die folgende Schleife verwendet continue , um nur ungerade Werte auszugeben:
for (sei i = 0; i < 10; i++) {
// wenn wahr, den verbleibenden Teil des Körpers überspringen
if (i % 2 == 0) continue;
alarm(i); // 1, dann 3, 5, 7, 9
} Für gerade Werte von i stoppt die continue Direktive die Ausführung des Hauptteils und übergibt die Kontrolle an die nächste Iteration von for (mit der nächsten Zahl). Der alert wird also nur bei ungeraden Werten ausgelöst.
Die continue Direktive trägt dazu bei, die Verschachtelung zu verringern
Eine Schleife, die ungerade Werte anzeigt, könnte so aussehen:
for (sei i = 0; i < 10; i++) {
if (i % 2) {
alarm( i );
}
} Aus technischer Sicht ist dies identisch mit dem obigen Beispiel. Sicherlich können wir den Code einfach in einen if Block einschließen, anstatt continue zu verwenden.
Aber als Nebeneffekt entstand dadurch eine weitere Verschachtelungsebene (der alert innerhalb der geschweiften Klammern). Wenn der Code in if länger als ein paar Zeilen ist, kann dies die allgemeine Lesbarkeit beeinträchtigen.
Kein break/continue zur rechten Seite von „?“
Bitte beachten Sie, dass Syntaxkonstrukte, die keine Ausdrücke sind, nicht mit dem ternären Operator verwendet werden können ? . Insbesondere sind Anweisungen wie break/continue dort nicht erlaubt.
Nehmen wir zum Beispiel diesen Code:
wenn (i > 5) {
alarm(i);
} anders {
weitermachen;
}…und schreiben Sie es mit einem Fragezeichen um:
(i > 5)? alarm(i): fortfahren; // Weiter ist hier nicht erlaubt
…es funktioniert nicht mehr: Es liegt ein Syntaxfehler vor.
Dies ist nur ein weiterer Grund, den Fragezeichenoperator nicht zu verwenden ? statt if .
Manchmal müssen wir aus mehreren verschachtelten Schleifen gleichzeitig ausbrechen.
Im folgenden Code durchlaufen wir beispielsweise i und j und fordern die Koordinaten (i, j) von (0,0) bis (2,2) an:
for (sei i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
let input = prompt(`Value at coords (${i},${j})`, '');
// Was ist, wenn wir von hier aus zu „Fertig“ (unten) wechseln möchten?
}
}
alarm('Fertig!');Wir brauchen eine Möglichkeit, den Prozess zu stoppen, wenn der Benutzer die Eingabe abbricht.
Die normale break nach input würde nur die innere Schleife unterbrechen. Das reicht nicht – Etiketten, kommen Sie zur Rettung!
Ein Label ist ein Bezeichner mit einem Doppelpunkt vor einer Schleife:
labelName: für (...) {
...
} Die break <labelName> -Anweisung in der Schleife unten führt zum Label aus:
außen: for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
let input = prompt(`Value at coords (${i},${j})`, '');
// wenn eine leere Zeichenfolge oder abgebrochen, dann brechen Sie beide Schleifen ab
if (!input) break äußere; // (*)
// etwas mit dem Wert machen...
}
}
alarm('Fertig!'); Im obigen Code sucht break outer nach oben nach der Bezeichnung outer und bricht aus dieser Schleife aus.
Die Steuerung geht also direkt von (*) zu alert('Done!') .
Wir können die Beschriftung auch in eine separate Zeile verschieben:
äußere:
for (sei i = 0; i < 3; i++) { ... } Die continue Direktive kann auch mit einem Label verwendet werden. In diesem Fall springt die Codeausführung zur nächsten Iteration der gekennzeichneten Schleife.
Etiketten erlauben es nicht, irgendwohin zu „springen“.
Labels erlauben es uns nicht, an eine beliebige Stelle im Code zu springen.
Dies ist zum Beispiel nicht möglich:
Bruchetikett; // zum Label unten springen (funktioniert nicht) Etikett: für (...)
Eine break Direktive muss sich innerhalb eines Codeblocks befinden. Technisch gesehen reicht jeder beschriftete Codeblock aus, z. B.:
Etikett: {
// ...
Bruchetikett; // funktioniert
// ...
} … Allerdings werden 99,9 % der break innerhalb von Schleifen verwendet, wie wir in den obigen Beispielen gesehen haben.
Eine continue ist nur innerhalb einer Schleife möglich.
Wir haben drei Arten von Schleifen behandelt:
while – Die Bedingung wird vor jeder Iteration überprüft.
do..while – Die Bedingung wird nach jeder Iteration überprüft.
for (;;) – Die Bedingung wird vor jeder Iteration überprüft, zusätzliche Einstellungen verfügbar.
Um eine „Endlosschleife“ zu erstellen, wird normalerweise das while(true) -Konstrukt verwendet. Eine solche Schleife kann, wie jede andere auch, mit der break Direktive gestoppt werden.
Wenn wir in der aktuellen Iteration nichts tun möchten und mit der nächsten fortfahren möchten, können wir die continue -Direktive verwenden.
Unterstützungsetiketten vor der Schleife break/continue . Eine Bezeichnung ist die einzige Möglichkeit für break/continue , einer verschachtelten Schleife zu entkommen und zu einer äußeren zu gelangen.
Wichtigkeit: 3
Was ist der letzte Wert, der von diesem Code gemeldet wird? Warum?
sei i = 3;
während (i) {
alarm( i-- );
}
Die Antwort: 1 .
sei i = 3;
während (i) {
alarm( i-- );
} Jede Schleifeniteration verringert i um 1 . Die Prüfung while(i) stoppt die Schleife, wenn i = 0 .
Somit bilden die Schritte der Schleife die folgende Reihenfolge („Schleife abgerollt“):
sei i = 3; alarm(i--); // zeigt 3, verringert i auf 2 alarm(i--) // zeigt 2, verringert i auf 1 alarm(i--) // zeigt 1, verringert i auf 0 // fertig, while(i) check stoppt die Schleife
Wichtigkeit: 4
Notieren Sie für jede Schleifeniteration, welchen Wert sie ausgibt, und vergleichen Sie ihn dann mit der Lösung.
Beide Schleifen alert die gleichen Werte, oder nicht?
Die Präfixform ++i :
sei i = 0; while (++i < 5) alarm( i );
Die Postfixform i++
sei i = 0; while (i++ < 5) alarm( i );
Die Aufgabe zeigt, wie Postfix-/Präfixformen bei Vergleichen zu unterschiedlichen Ergebnissen führen können.
Von 1 bis 4
sei i = 0; while (++i < 5) alarm( i );
Der erste Wert ist i = 1 , da ++i zuerst i inkrementiert und dann den neuen Wert zurückgibt. Der erste Vergleich ist also 1 < 5 und die alert zeigt 1 an.
Dann folgen 2, 3, 4… – die Werte werden nacheinander angezeigt. Der Vergleich verwendet immer den inkrementierten Wert, da ++ vor der Variablen steht.
Schließlich wird i = 4 auf 5 erhöht, der Vergleich while(5 < 5) schlägt fehl und die Schleife stoppt. Daher wird 5 nicht angezeigt.
Von 1 bis 5
sei i = 0; while (i++ < 5) alarm( i );
Der erste Wert ist wieder i = 1 . Die Postfixform von i++ erhöht i und gibt dann den alten Wert zurück, sodass beim Vergleich i++ < 5 i = 0 verwendet wird (im Gegensatz zu ++i < 5 ).
Der alert ist jedoch separat. Es handelt sich um eine weitere Anweisung, die nach der Inkrementierung und dem Vergleich ausgeführt wird. Es erhält also den Strom i = 1 .
Dann folgen Sie 2, 3, 4…
Bleiben wir bei i = 4 stehen. Die Präfixform ++i würde es erhöhen und 5 im Vergleich verwenden. Aber hier haben wir die Postfix-Form i++ . Es erhöht also i auf 5 , gibt aber den alten Wert zurück. Daher ist der Vergleich tatsächlich while(4 < 5) – wahr, und die Steuerung geht zu alert über.
Der Wert i = 5 ist der letzte, da im nächsten Schritt while(5 < 5) falsch ist.
Wichtigkeit: 4
Notieren Sie für jede Schleife, welche Werte sie anzeigen soll. Vergleichen Sie dann mit der Antwort.
Beide Schleifen alert die gleichen Werte oder nicht?
Das Postfix-Formular:
for (let i = 0; i < 5; i++) alarm( i );
Die Präfixform:
for (let i = 0; i < 5; ++i) alarm( i );
Die Antwort: in beiden Fällen von 0 bis 4 .
for (let i = 0; i < 5; ++i) alarm( i ); for (let i = 0; i < 5; i++) alarm( i );
Das lässt sich leicht aus dem Algorithmus von for ableiten:
Einmal i = 0 vor allem ausführen (beginnen).
Überprüfen Sie die Bedingung i < 5
Wenn true – führen Sie den Schleifenkörper alert(i) und dann i++ aus
Das Inkrement i++ ist von der Bedingungsprüfung (2) getrennt. Das ist nur eine weitere Aussage.
Der vom Inkrement zurückgegebene Wert wird hier nicht verwendet, daher gibt es keinen Unterschied zwischen i++ und ++i .
Wichtigkeit: 5
Verwenden Sie die for Schleife, um gerade Zahlen von 2 bis 10 auszugeben.
Führen Sie die Demo aus
for (sei i = 2; i <= 10; i++) {
if (i % 2 == 0) {
alarm( i );
}
} Wir verwenden den „Modulo“-Operator % um den Rest zu ermitteln und prüfen hier die Gleichmäßigkeit.
Wichtigkeit: 5
Schreiben Sie den Code neu und ändern Sie die for Schleife in while ohne ihr Verhalten zu ändern (die Ausgabe sollte gleich bleiben).
for (sei i = 0; i < 3; i++) {
alarm( `Nummer ${i}!` );
}
sei i = 0;
while (i < 3) {
alarm( `Nummer ${i}!` );
i++;
}Wichtigkeit: 5
Schreiben Sie eine Schleife, die zur Eingabe einer Zahl größer als 100 auffordert. Wenn der Besucher eine andere Nummer eingibt, bitten Sie ihn, die Nummer erneut einzugeben.
Die Schleife muss nach einer Zahl fragen, bis der Besucher entweder eine Zahl größer als 100 eingibt oder die Eingabe abbricht bzw. eine leere Zeile eingibt.
Hier können wir davon ausgehen, dass der Besucher nur Zahlen eingibt. In dieser Aufgabe ist es nicht erforderlich, eine spezielle Behandlung für eine nicht numerische Eingabe zu implementieren.
Führen Sie die Demo aus
lass num;
Tun {
num = prompt("Geben Sie eine Zahl größer als 100 ein?", 0);
} while (num <= 100 && num); Die Schleife do..while wird wiederholt, solange beide Prüfungen wahr sind:
Die Prüfung auf num <= 100 , d. h. der eingegebene Wert ist immer noch nicht größer als 100 .
Die Prüfung && num ist falsch, wenn num null oder eine leere Zeichenfolge ist. Dann stoppt auch die while Schleife.
PS: Wenn num null ist, ist num <= 100 true . Ohne die zweite Prüfung würde die Schleife also nicht anhalten, wenn der Benutzer auf CANCEL klickt. Beide Prüfungen sind erforderlich.
Wichtigkeit: 3
Eine ganze Zahl größer als 1 wird Primzahl genannt, wenn sie nur durch 1 und sich selbst ohne Rest geteilt werden kann.
Mit anderen Worten: n > 1 ist eine Primzahl, wenn sie nur durch 1 und n gleichmäßig geteilt werden kann.
Beispielsweise ist 5 eine Primzahl, da sie nicht ohne Rest durch 2 , 3 und 4 geteilt werden kann.
Schreiben Sie den Code, der Primzahlen im Intervall von 2 bis n ausgibt.
Für n = 10 ist das Ergebnis 2,3,5,7 .
PS: Der Code sollte für alle n funktionieren und nicht auf einen festen Wert abgestimmt sein.
Für diese Aufgabe gibt es viele Algorithmen.
Lassen Sie uns eine verschachtelte Schleife verwenden:
Für jedes i im Intervall {
Überprüfen Sie, ob ich einen Teiler von 1..i habe
wenn ja => der Wert ist keine Primzahl
Wenn nein => der Wert ist eine Primzahl, zeige ihn
}Der Code mit einem Etikett:
sei n = 10;
nextPrime:
for (let i = 2; i <= n; i++) { // für jedes i...
for (let j = 2; j < i; j++) { // Suche nach einem Teiler..
if (i % j == 0) continue nextPrime; // keine Primzahl, gehe als nächstes i
}
alarm( i ); // eine Primzahl
} Es gibt viel Raum zur Optimierung. Beispielsweise könnten wir nach den Teilern von 2 bis zur Quadratwurzel von i suchen. Aber wenn wir bei großen Intervallen wirklich effizient sein wollen, müssen wir den Ansatz ändern und uns auf fortgeschrittene Mathematik und komplexe Algorithmen wie quadratisches Sieb, allgemeines Zahlenfeldsieb usw. verlassen.