[ Web Proxy ]
URL:
Viewing: https://it.javascript.info/while-for [Back]  [Original]

Cicli: while e for
IT

Vorremo rendere disponibile questo progetto open-source per persone in tutto il mondo.

Aiutaci a tradurre il contenuto di questo tutorial nella tua lingua!

    Cerca in Javascript.info:
    Cerca nel tutorial:
    Light themeDark theme
    DanskEnglishEspaolFranaisIndonesiaItalianoTrkeOzbek

    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--;
    }
    Le parentesi non sono richieste per un corpo composto da una singola linea di codice

    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
    Dichiarazioni di variabili inline

    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.

    La direttiva continue aiuta a diminuire i livelli di nidificazione

    Un 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.

    Vietato 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 equivalgono a goto

    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:

    • while La condizione viene controllata prima di ogni iterazione.
    • do..while La 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.

    Esercizi

    importanza: 3

    Qual lultimo valore mostrato da alert in questo codice? Perch?

    let i = 3;
    
    while (i) {
      alert( i-- );
    }
    soluzione

    La risposta : 1.

    let i = 3;
    
    while (i) {
      alert( i-- );
    }

    Ogni iterazione del ciclo decrementa i di 1. Il controllo while(i) interrompe il ciclo quando i = 0.

    Quindi, gli step del ciclo sono (loop unrolled):

    let i = 3;
    
    alert(i--); //mostra 3, decrementa i a 2
    
    alert(i--) // mostra 2, decrementa i a 1
    
    alert(i--) // mostra 1, decrementa i a 0
    
    // finito, `i`  ora 0, che convertito a booleano  falso
    importanza: 4

    Per ogni iterazione del ciclo, scrivi quali valori verranno mostrati e poi confrontali con la soluzione.

    Entrambi i cicli mostreranno gli stessi valori in alert, o no?

    1. La forma prefissa ++i:

      let i = 0;
      while (++i < 5) alert( i );
    2. La forma postfissa i++

      let i = 0;
      while (i++ < 5) alert( i );
    soluzione

    Lesercizio dimostrava come le forme prefissa/postfissa possono portare a risultati differenti.

    1. Da 1 a 4

      let i = 0;
      while (++i < 5) alert( i );

      Il primo valore i = 1, perch ++i incrementa prima i e poi ritorna il nuovo valore. Quindi il primo confronto 1 < 5 e alert mostra 1.

      Poi seguono 2, 3, 4 i valori vengono mostrati uno dopo laltro. Il confronto utilizza sempre il valore incrementato, perch ++ posto prima della variabile.

      Ultima iterazione, i = 4 viene incrementato a 5, il confronto while(5 < 5) risulta false, e il ciclo termina. 5 non viene mostrato.

    2. Da 1 a 5

      let i = 0;
      while (i++ < 5) alert( i );

      Il primo valore ancora i = 1. La forma postfissa i++ incrementa i e ritorna il vecchio valore, quindi il confronto i++ < 5 utilizza i = 0 (a differenza di ++i < 5).

      La chiamata ad alert separata. E un istruzione che viene eseguita dopo lincremento di i e il controllo della condizione. Quindi i = 1.

      Seguono 2, 3, 4

      Fermiamoci a i = 4. La forma prefissa ++i incrementerebbe ed utilizzerebbe 5 nel controllo della condizione i < 5. Qui per stiamo usando la forma postfissa i++. Quindi incrementa ia 5, ma ritorna il vecchio valore. Il confronto dunque while(4 < 5) vero; il controllo passa alla chiamata alert.

      Il valore i = 5 lultimo, perch nelliterazione successiva avremmo while(5 < 5) e la condizione sarebbe falsa.

    importanza: 4

    Per ogni ciclo scrivete quali valori verranno mostrati. Poi confrontateli con la soluzione.

    I due alert mostreranno gli stessi valori?

    1. Forma postfissa:

      for (let i = 0; i < 5; i++) alert( i );
    2. Forma prefissa:

      for (let i = 0; i < 5; ++i) alert( i );
    soluzione

    La risposta: da 0 a 4 in entrambi i casi.

    for (let i = 0; i < 5; ++i) alert( i );
    
    for (let i = 0; i < 5; i++) alert( i );

    Questo pu essere facilmente dedotto dallalgoritmo for:

    1. Esegue come prima cosa i = 0 (una sola volta)
    2. Verifica la condizione i < 5
    3. Se true esegue il corpo del ciclo, dove si trova alert(i), poi incrementa i di 1

    Lincremento i++ separato dal controllo della condizione(2). E unistruzione differente.

    Il valore ritornato non viene utilizzato, quindi non c differenza tra i++ e ++i.

    importanza: 5

    Utilizzate il ciclo for per mostrare i numeri pari da 2 a 10.

    Esegui la demo

    soluzione
    for (let i = 2; i <= 10; i++) {
      if (i % 2 == 0) {
        alert( i );
      }
    }

    Utilizziamo loperatore modulo % per controllare che un numero sia pari.

    importanza: 5

    Riscrivi il ciclo for utilizzando la sintassi while, ma senza alterarne la funzionalit (loutput deve rimanere lo stesso).

    for (let i = 0; i < 3; i++) {
      alert( `number ${i}!` );
    }
    soluzione
    let i = 0;
    while (i < 3) {
      alert( `number ${i}!` );
      i++;
    }
    importanza: 5

    Scrivi un ciclo che richieda (tramite prompt) un numero maggiore di 100. Se lutente inserisce un numero non valido chiedete di inserirlo nuovamente.

    Il ciclo deve continuare a richiede un numero fintanto che lutente non inserisce un numero maggiore di 100, oppure annulla linput (sia premendo cancel che inserendo una riga vuota).

    Possiamo assumere che lutente inserisca solo numeri. Non c quindi bisogno di implementare alcun tipo di logica per un input di tipo non numerico.

    Esegui la demo

    soluzione
    let num;
    
    do {
      num = prompt("Enter a number greater than 100?", 0);
    } while (num <= 100 && num);

    Il ciclo do..while si ripete fintanto che entrambe le condizioni non risultano vere:

    1. Il controllo num <= 100 controlla se il valore non risulti ancora maggiore di 100.
    2. Il controllo && num diventa falso quando num null o una stringa. Quindi il ciclo while termina.

    P.S. Se num null allora la condizione num <= 100 true, quindi senza la seconda condizione il ciclo non terminerebbe nel caso in cui lutente prema CANCEL. Entrambe le condizioni sono necessarie.

    importanza: 3

    Un valore intero maggiore di 1 si definisce primo se non pu essere diviso, senza resto, da nessun numero ad eccezione di 1 e se stesso.

    In altre parole, n > 1 primo se non pu essere diviso da nessun altro numero ad eccezione di 1 e n.

    Ad esempio, 5 primo perch non pu essere diviso senza resto da 2, 3 o 4.

    scrivi un codice che mostri i numeri primi nellintervallo da 2 a n.

    Per n = 10 il risultato sar 2,3,5,7.

    P.S. Il codice dovrebbe funzionare per qualsiasi numero n, non solo per un valore numerico prefissato.

    soluzione

    Ci sono diversi possibili algoritmi per il nostro scopo.

    Usiamo un ciclo annidato:

    For each i in the interval {
      check if i has a divisor from 1..i
      if yes => the value is not a prime
      if no => the value is a prime, show it
    }

    Il codice usa unetichetta:

    let n = 10;
    
    nextPrime:
    for (let i = 2; i <= n; i++) { // per ogni i...
    
      for (let j = 2; j < i; j++) { // controlla i suoi divisori..
        if (i % j == 0) continue nextPrime; // se  divisibile per uno di essi, non  un numero primo; passa a prossima iterazione
      }
    
      alert( i ); // un numero primo
    }

    Ci sono molti modi per ottimizzare questo algoritmo. Ad esempio, potremmo controllare i divisori di 2 fino alla radice di i. In ogni caso, se vogliamo essere veramete efficenti su grandi intervalli, abbiamo bisogno di cambiare approcio ed affidarci ad algoritmi matematici pi avanzati e complessi, come Quadratic sieve, General number field sieve etc.

    Mappa del tutorial

    Commenti

    leggi questo prima di lasciare un commento
    • Per qualsiasi suggerimento - per favore, apri una issue su GitHub o una pull request, piuttosto di lasciare un commento.
    • Se non riesci a comprendere quanto scitto nell'articolo ti preghiamo di fornire una spiegazione chiara.
    • Per inserire delle righe di codice utilizza il tag <code>, per molte righe includile nel tag <pre>, per pi di 10 righe utilizza una sandbox (plnkr, jsbin, codepen)

    Web Proxy Viewer  |  New URL  |  Original Page