Abbiamo spesso bisogno di eseguire la stessa azione pi volte di fila.
Ad esempio, quando abbiamo bisogno di ritornare, una dopo laltra, della merce da una lista; o anche solo eseguire lo stesso codice per ogni numero da 1 a 10.
I cicli sono un modo di ripetere una stessa parte di codice pi volte.
Il ciclo while
Il ciclo while ha la seguente sintassi:
while (condition) {
// codice
// "corpo del ciclo"
}
Fino a che la condition true, il code nel corpo del ciclo viene eseguito.
Ad esempio, il ciclo qui sotto mostra i fino a che i < 3:
let i = 0;
while (i < 3) { // mostra 0, poi 1, poi 2
alert( i );
i++;
}
Unesecuzione del codice nel corpo del ciclo viene chiamata uniterazione. Il ciclo nellesempio sopra fa tre iterazioni.
Se nellesempio sopra non ci fosse i++, il ciclo si ripeterebbe per sempre; in teoria: in pratica, il browser ha dei metodi per bloccare questi cicli. In JavaScript server-side necessario arrestare il processo.
Qualsiasi espressione o variabile pu essere utilizzata come condizione di un ciclo, non solo un confronto come i < 3. Il ciclo while converte le espressioni al tipo booleano, che vengono poi valutate.
Ad esempio, un modo pi breve di scrivere while (i != 0) potrebbe essere while (i):
let i = 3;
while (i) { // quando i diventa 0, la condizione diventa falsa e il ciclo si conclude
alert( i );
i--;
}
Se il corpo del ciclo ha una singola istruzione, possiamo omettere le parentesi {}:
let i = 3;
while (i) alert(i--);
Il ciclo dowhile
La condizione da controllare pu essere messa dopo il corpo del ciclo. Lo si fa utilizzando la sintassi do..while:
do {
// corpo del ciclo
} while (condition);
Il ciclo esegue prima il corpo, poi controlla la condizione; se questa vera, esegue nuovamente il corpo.
Ad esempio:
let i = 0;
do {
alert( i );
i++;
} while (i < 3);
Questa tipo di sintassi viene usata molto raramente, ad eccezione dei casi in cui si vuole che il corpo del ciclo venga eseguito almeno una volta. Questo avviene ancor prima del controllo della condizione. La forma pi comune, comunque, while() {}.
Il ciclo for
Il ciclo for forse il pi utilizzato.
La sua sintassi :
for (begin; condition; step) {
// ... corpo del ciclo ...
}
Cerchiamo ora di capire, tramite esempi, il suo funzionamento.
Il ciclo sotto esegue alert(i) fino a quando la variabile i pi piccola di 3. A ogni iterazione, il valore di i aumenta di 1.
for (let i = 0; i < 3; i++) { // mostra 0, poi 1, poi 2
alert(i);
}
Esaminiamo listruzione for parte per parte:
| Parte | ||
|---|---|---|
| begin | i = 0 |
Viene eseguito una volta sola, allentrata nel ciclo. |
| condition | i < 3 |
Viene controllata prima di ogni iterazione; se falsa, il ciclo si interrompe. |
| body | alert(i) |
Viene eseguito fino a quando la condizione vera. |
| step | i++ |
Viene eseguito ad ogni iterazione, dopo il corpo, fintato che la condizione true. |
Literazione, generalmente, funziona nel modo seguente:
Eseguiamo begin
(if condition run body and run step)
(if condition run body and run step)
(if condition run body and run step)
...
Ricapitolando: begin viene eseguito per primo, una volta sola; subito dopo, inizia literazione. Se condition, dopo la conversione a booleano, true, vengono eseguiti body e step; se false, il ciclo si interrompe.
Se i cicli vi sono nuovi, forse vi sar daiuto tornare indietro agli esempi e provare a riprodurli, passo passo, su un foglio di carta.
Ecco esattamente, in dettaglio, ci che avviene nel nostro codice:
// for (let i = 0; i < 3; i++) alert(i)
// inizia l'esecuzione, viene dichiarata la variabile i
let i = 0
// if(condition == true) esegue il corpo e avanza
if (i < 3) { alert(i); i++ }
// if(condition == true) esegue il corpo e avanza
if (i < 3) { alert(i); i++ }
// if(condition == true) esegue il corpo e avanza
if (i < 3) { alert(i); i++ }
// ...si conclude, perch ora i == 3 e la condizione i < 3 == false
Qui il counter, che utilizzeremo nella nostra condition, una variabile: i. Viene dichiarata allinterno del corpo del ciclo ed accessibile solo al suo interno. Questo tipo di espressione si chiama dichiarazione di una variabile inline.
for (let i = 0; i < 3; i++) { //'i' definito, e accessibile, solo dentro il corpo del ciclo
alert(i); // 0, 1, 2
}
alert(i); // errore, nessuna variabile 'i' fuori dal corpo del ciclo
Invece di definire una nuova variabile, possiamo utilizzarne una gi esistente:
let i = 0;
for (i = 0; i < 3; i++) { // utilizza una variabile esistente
alert(i); // 0, 1, 2
}
alert(i); // 3; la variabile `i` accessibile ( stata dichiarata fuori dal corpo del ciclo)
Parti opzionali
Ogni parte del ciclo for opzionale.
Ad esempio, possiamo omettere begin se non abbiamo bisogno di una variabile per la nostra condition.
Come in questo esempio:
let i = 0; // la variabile 'i' stata gi dichiarata e assegnata
for (; i < 3; i++) { // saltiamo "begin"
alert( i ); // 0, 1, 2
}
Possiamo anche rimuovere lostep:
let i = 0;
for (; i < 3;) {
alert( i++ ); //la variabile 'i' viene incrementata nel corpo del ciclo
}
Il ciclo, nellesempio sopra, diventa uguale ad un while (i < 3).
Possiamo rimuovere tutto, ma questo risulterebbe in un ciclo infinito:
for (;;) {
// esegue il corpo del ciclo senza mai terminare
}
Nota che le due ; del ciclo for devono essere presenti, altrimenti vi sarebbe un errore di sintassi.
Interrompere un ciclo
Normalmente un ciclo termina quando la condizione diventa falsa.
Ma possibile forzare luscita in qualsiasi momento. C una speciale direttiva per fare questo: break.
Ad esempio, il ciclo sotto richiede allutente una serie di numeri, e termina quando nessun numero viene inserito:
let sum = 0;
while (true) {
let value = +prompt("Enter a number", '');
if (!value) break; // (*)
sum += value;
}
alert( 'Sum: ' + sum );
La direttiva break viene attivata alla linea (*), quando lutente inserisce una linea vuota o annulla la procedura di input. Questo ferma il ciclo immediatamente, passando il controllo alla prima linea successiva al ciclo. In questo caso, alert.
La combinazione ciclo infinito + break quando necessario utile in situazioni in cui la condizione deve essere verificata in un punto differente dallinizio/fine del ciclo (questo pu avvenire in un qualsiasi altro punto del corpo).
Vai alla prossima iterazione
La direttiva continue una versione leggera del break. Non blocca lintero ciclo: interrompe solo literazione corrente e forza il ciclo a passare alliterazione successiva.
Possiamo utilizzarla se abbiamo finito con le operazioni che ci interessano e vogliamo passare alliterazione seguente.
Il ciclo sotto usa continue per ritornare solo i valori dispari:
for (let i = 0; i < 10; i++) {
// se condizione == true (`i` pari) salta la restante parte di codice a passa alla prossima iterazione
if (i % 2 == 0) continue;
//se `i` dispari, esegui codice
alert(i); // 1, poi 3, 5, 7, 9 (nota le due condizioni sopra: abbiamo solo i con un valore dispari, e inferiore a 10)
}
Per i valori pari di i la direttiva continue interrompe lesecuzione del corpo e passa il controllo alla successiva iterazione del for (i viene incrementato, poi si controlla che la condizione sia true). Di conseguenza, lalert viene seguito solo con i valori dispari.
continue aiuta a diminuire i livelli di nidificazioneUn ciclo che mostra solo valori dispari potrebbe essere:
for (let i = 0; i < 10; i++) {
if (i % 2) { //la condizione == 0 quando un numero pari; 0, ricordiamo, convertito a booleano, false
alert( i );
}
}
Ovviamente possiamo raccogliere il codice in un blocco if piuttosto di usare continue. Dal punto di vista tecnico lesempio sopra identico a quello che lo precede, che invece utilizza continue. Nellesempio sopra il codice dentro il corpo di if una semplice chiamata ad alert; ma se il codice fosse pi lungo di un paio di righe si rischierebbe di perdere in leggibilit.
break/continue alla desta di ?Va notato che questo costrutto sintattico non un espressione e non pu quindi essere utilizzato con loperatore ternario ?. In particolare, direttive come break/continue non sono permesse.
Ad esempio, se prendiamo questo codice:
if (i > 5) {
alert(i);
} else {
continue;
}
E lo riscriviamo utilizzando loperatore ternario:
(i > 5) ? alert(i) : continue; // continue non consentito qui
Questo smetter di funzionare. Un codice come quello sopra risulter in un errore di sintassi:
Questa solo unaltra ragione per cui non utilizzare loperatore ternario ? piuttosto di if.
Etichette break/continue
Qualche volta abbiamo bisogno di uscire da una serie di cicli annidati in un colpo solo.
Ad esempio, nel codice sotto abbiamo due cicli for che usano (i, j) nelle proprie condizioni; fino a quando le variabili sono minori di 3, il ciclo viene eseguito; dentro al ciclo pi interno un prompt mostra le due variabili
(i, j) in una stringa di testo:
for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
let input = prompt(`Value at coords (${i},${j})`, '');
// come potremmo fare per uscire di qui e proseguire verso Done (sotto)?
}
}
alert('Done!');
Abbiamo bisogno di un modo per bloccare il processo se lutente annulla linput.
Un semplice break dopo la variabile input interromperebbe solo il ciclo pi interno. Questo non sufficiente. I label ci vengono in soccorso.
Un label (etichetta) un identificatore seguito da : e da un ciclo:
labelName: for (...) {
...
}
Listruzione break <labelName> interrompe il ciclo e passa il controllo a label.
Come nellesempio:
outer: for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
let input = prompt(`Value at coords (${i},${j})`, '');
// se si ha una stringa vuota, allora si esce da entrambi i cicli
if (!input) break outer; // (*)
// fa qualcosa con i valori...
}
}
alert('Done!');
Nel codice sopra break outer interrompe il ciclo e va alletichetta chiamata outer.
Quindi il controllo va da (*) a alert('Done!').
Possiamo anche spostare letichetta in unaltra linea:
outer:
for (let i = 0; i < 3; i++) { ... }
Anche la direttiva continue pu essere utilizzata con unetichetta. In questo caso lesecuzione salta alla prossima iterazione del ciclo con quelletichetta.
I label non permettono di saltare in un punto arbitrario del codice.
Ad esempio, non possibile:
break label; // non salta all'etichetta sotto
label: for (...)
La direttiva break deve essere allinterno del blocco di codice. Tecnicamente letichettatura funzioner con qualsiasi blocco di codice, ad esempio:
label: {
// ...
break label; // funziona
// ...
}
Comunque, nel 99.9% dei casi, break viene usato nei cicli, come abbiamo visto negli esempi precedenti.
La chiamata a continue possibile solo dallinterno di un ciclo
Riepilogo
Abbiamo visto tre tipi di cicli:
whileLa condizione viene controllata prima di ogni iterazione.do..whileLa condizione viene controllata dopo una prima iterazione.for (;;)La condizione viene controllata prima di ogni iterazione; sono possibili altre condizioni allinterno del ciclo.
Per creare un ciclo infinito, si usa il costrutto while(true). Questo tipo di cicli, come tutti gli altri, possono essere interrotti con la direttiva break.
Se non si ha pi intenzione di fare nulla nelliterazione corrente e si vuole quindi saltare alla successiva, possiamo usare la direttiva continue.
break/continue supportano le etichette prima del ciclo. Un etichetta lunico modo per break/continue di uscire da cicli annidati ed arrivare ciclo esterno.
Commenti
<code>, per molte righe includile nel tag<pre>, per pi di 10 righe utilizza una sandbox (plnkr, jsbin, codepen)