034.3 Lezione 1
Certificazione: |
Web Development Essentials |
---|---|
Versione: |
1.0 |
Argomento: |
034 Programmazione JavaScript |
Obiettivo: |
034.3 Strutture di Controllo e Funzioni in JavaScript |
Lezione: |
1 di 2 |
Introduzione
Come qualsiasi altro linguaggio di programmazione il codice JavaScript è un insieme di dichiarazioni che dicono a un interprete di istruzioni che cosa fare in ordine sequenziale. Tuttavia, questo non significa che ogni istruzione debba essere eseguita solo una volta o che debba essere eseguita affatto. La maggior parte delle istruzioni dovrebbe essere eseguita solo quando si verificano condizioni specifiche. Anche quando uno script è attivato in modo asincrono da eventi indipendenti, spesso deve controllare un certo numero di variabili di controllo per trovare la giusta porzione di codice da eseguire.
Dichiarazioni If
La struttura di controllo più semplice è data dall’istruzione if
, che eseguirà l’istruzione immediatamente successiva se la condizione specificata è vera. JavaScript considera le condizioni vere se il valore valutato è diverso da zero. Qualsiasi cosa all’interno della parentesi dopo la parola if
(gli spazi sono ignorati) sarà interpretata come una condizione. Nell’esempio seguente, il numero letterale 1
è la condizione:
if ( 1 ) console.log("1 is always true");
Il numero 1
è scritto esplicitamente in questa condizione di esempio, quindi è trattato come un valore costante (rimane lo stesso durante l’esecuzione dello script) e darà sempre come risultato vero quando viene usato come espressione condizionale. La parola true
(senza le doppie virgolette) potrebbe anche essere usata al posto di 1
, dato che è anche trattata come un valore letterale vero dal linguaggio. L’istruzione console.log
mostra i suoi argomenti nella console del browser.
Tip
|
La console del browser mostra errori, avvisi e messaggi informativi inviati con l’istruzione JavaScript |
Anche se sintatticamente corretto, usare espressioni costanti nelle condizioni non è molto utile. In un’applicazione reale, probabilmente vorresti testare la veridicità di una variabile:
let my_number = 3;
if ( my_number ) console.log("The value of my_number is", my_number, "and it yields true");
Il valore assegnato alla variabile my_number (3)
non è zero, quindi produce true. Ma questo esempio non è di uso comune, perché raramente si ha bisogno di verificare se un numero è uguale a zero. È molto più comune confrontare un valore con un altro e verificare se il risultato è vero:
let my_number = 3;
if ( my_number == 3 ) console.log("The value of my_number is", my_number, "indeed");
L’operatore di confronto doppio-uguale (==
) viene utilizzato perché l’operatore uguale (=
) è già definito come operatore di assegnazione. Il valore su ciascun lato dell’operatore è chiamato operando. L’ordine degli operandi non ha importanza e qualsiasi espressione che restituisce un valore può essere un operando. Ecco un elenco di altri operatori di confronto disponibili:
value1 == value2
-
Vero se
value1
è uguale avalue2
. value1 != value2
-
Vero se
value1
non è uguale avalue2
. value1 < value2
-
Vero se
value1
è minore divalue2
. value1 > value2
-
Vero se
value1
è maggiore divalue2
. value1 <= value2
-
Vero se
value1
è minore o uguale avalue2
. value1 >= value2
-
Vero se
value1
è maggiore o uguale avalue2
.
Di solito, non importa se l’operando a sinistra dell’operatore è una stringa e l’operando a destra è un numero, purché JavaScript sia in grado di convertire l’espressione in un confronto significativo. Quindi la stringa contenente il carattere 1
sarà trattata come il numero 1 rispetto a una variabile numerica. Per assicurarsi che l’espressione restituisca true solo se entrambi gli operandi sono dello stesso tipo e valore, è necessario utilizzare l’operatore di identità rigorosa ===
invece di ==
. Allo stesso modo, l’operatore stretto di non identità !==
viene valutato come true se il primo operando non è dello stesso tipo e valore del secondo operatore.
Opzionalmente, la struttura di controllo if
può eseguire un’istruzione alternativa quando l’espressione viene valutata come falsa:
let my_number = 4;
if ( my_number == 3 ) console.log("The value of my_number is 3");
else console.log("The value of my_number is not 3");
L’istruzione else
dovrebbe seguire immediatamente l’istruzione if
. Finora stiamo eseguendo solo un’istruzione quando la condizione è soddisfatta. Per eseguire più di un’istruzione, devi racchiuderle tra parentesi graffe:
let my_number = 4;
if ( my_number == 3 )
{
console.log("The value of my_number is 3");
console.log("and this is the second statement in the block");
}
else
{
console.log("The value of my_number is not 3");
console.log("and this is the second statement in the block");
}
Un gruppo di una o più istruzioni delimitate da una coppia di parentesi graffe è noto come _ dichiarazione di blocco_. È comune usare dichiarazioni di blocco anche quando c’è una sola istruzione da eseguire, per rendere lo stile di codifica coerente in tutto lo script. Inoltre, JavaScript non richiede che le parentesi graffe o qualsiasi dichiarazione siano su linee separate, ma farlo migliora la leggibilità e rende più facile la manutenzione del codice.
Le strutture di controllo possono essere annidate l’una dentro l’altra, ma è importante non confondere le parentesi graffe di apertura e di chiusura di ogni dichiarazione di blocco:
let my_number = 4;
if ( my_number > 0 )
{
console.log("The value of my_number is positive");
if ( my_number % 2 == 0 )
{
console.log("and it is an even number");
}
else
{
console.log("and it is an odd number");
}
} // end of if ( my_number > 0 )
else
{
console.log("The value of my_number is less than or equal to 0");
console.log("and I decided to ignore it");
}
Le espressioni valutate dall’istruzione if
possono essere più elaborate di semplici confronti. Questo è il caso dell’esempio precedente, in cui l’espressione aritmetica my_number % 2
è stata impiegata all’interno delle parentesi nell’istruzione nidificata if
. L’operatore %
restituisce il resto dopo aver diviso il numero alla sua sinistra per il numero alla sua destra. Gli operatori aritmetici come %
hanno la precedenza sugli operatori di confronto come ==
, quindi il confronto utilizzerà il risultato dell’espressione aritmetica come operando sinistro.
In molte situazioni le strutture condizionali annidate possono essere combinate in una singola struttura usando gli operatori logici. Se fossimo interessati solo ai numeri pari positivi, per esempio, si potrebbe usare una singola struttura if:
let my_number = 4;
if ( my_number > 0 && my_number % 2 == 0 )
{
console.log("The value of my_number is positive");
console.log("and it is an even number");
}
else
{
console.log("The value of my_number either 0, negative");
console.log("or it is a negative number");
}
Il doppio operatore &&
(ampersand) nell’espressione valutata è l’operatore logico AND. Valuta come vero solo se l’espressione alla sua sinistra e l’espressione alla sua destra sono vere. Se vuoi abbinare numeri che siano positivi o pari, dovresti invece usare l’operatore ||
, che sta per l’operatore logico OR:
let my_number = -4;
if ( my_number > 0 || my_number % 2 == 0 )
{
console.log("The value of my_number is positive");
console.log("or it is a even negative number");
}
In questo esempio, solo i numeri dispari negativi non corrisponderanno ai criteri imposti dall’espressione composta. Se avete l’intento opposto, cioè di far corrispondere solo i numeri dispari negativi, aggiungi l’operatore logico NOT !
all’inizio dell’espressione:
let my_number = -5;
if ( ! ( my_number > 0 || my_number % 2 == 0 ) )
{
console.log("The value of my_number is an odd negative number");
}
L’aggiunta delle parentesi nell’espressione composta forza l’espressione racchiusa da esse a essere valutata per prima. Senza queste parentesi l’operatore NOT si applicherebbe solo a my_number > 0
e poi verrebbe valutata l’espressione OR. Gli operatori &&
e ||
sono conosciuti come operatori logici binari, perché richiedono due operandi. !
è conosciuto come operatore logico unario, perché richiede “un solo” operando.
Strutture di Commutazione
Sebbene la struttura if
sia abbastanza versatile e sufficiente per controllare il flusso del programma, la struttura di controllo switch
può essere più appropriata quando occorre valutare risultati diversi da vero o falso. Per esempio, se vogliamo intraprendere un’azione distinta per ogni elemento scelto da una lista, sarà necessario scrivere una struttura if
per ogni valutazione:
// Available languages: en (English), es (Spanish), pt (Portuguese)
let language = "pt";
// Variable to register whether the language was found in the list
let found = 0;
if ( language == "en" )
{
found = 1;
console.log("English");
}
if ( found == 0 && language == "es" )
{
found = 1;
console.log("Spanish");
}
if ( found == 0 && language == "pt" )
{
found = 1;
console.log("Portuguese");
}
if ( found == 0 )
{
console.log(language, " is unknown to me");
}
In questo esempio, una variabile ausiliaria found
è usata da tutte le strutture if
per scoprire se si è verificata una corrispondenza. In un caso come questo, la struttura switch
svolgerà lo stesso compito, ma in modo più succinto:
switch ( language )
{
case "en":
console.log("English");
break;
case "es":
console.log("Spanish");
break;
case "pt":
console.log("Portuguese");
break;
default:
console.log(language, " not found");
}
Ogni case
annidato è chiamato clausola. Quando una clausola corrisponde all’espressione valutata, esegue le istruzioni che seguono i due punti fino all’istruzione break
. L’ultima clausola non ha bisogno di un’istruzione break
ed è spesso usata per impostare l’azione predefinita quando non ci sono altre corrispondenze. Come visto nell’esempio, la variabile ausiliaria non è necessaria nella struttura switch
.
Warning
|
|
Se più di una clausola fa scattare la stessa azione, si possono combinare due o più condizioni case
:
switch ( language )
{
case "en":
case "en_US":
case "en_GB":
console.log("English");
break;
case "es":
console.log("Spanish");
break;
case "pt":
case "pt_BR":
console.log("Portuguese");
break;
default:
console.log(language, " not found");
}
Cicli
Negli esempi precedenti, le strutture if
e switch
erano ben adatte a compiti che devono essere eseguiti solo una volta dopo aver passato uno o più test condizionali. Tuttavia, ci sono situazioni in cui un compito deve essere eseguito ripetutamente — in un cosiddetto loop — finché la sua espressione condizionale continua a risultare vera. Se avete bisogno di sapere se un numero è primo, per esempio, dovrete controllare se dividendo questo numero per qualsiasi intero maggiore di 1 e minore di se stesso si ha un resto uguale a 0. Se è così, il numero ha un fattore intero e non è primo. (Questo non è un metodo rigoroso o efficiente per trovare i numeri primi, ma funziona come semplice esempio). Le strutture di controllo dei loop sono più adatte a questi casi, in particolare l’istruzione while
:
// A naive prime number tester
// The number we want to evaluate
let candidate = 231;
// Auxiliary variable
let is_prime = true;
// The first factor to try
let factor = 2;
// Execute the block statement if factor is
// less than candidate and keep doing it
// while factor is less than candidate
while ( factor < candidate )
{
if ( candidate % factor == 0 )
{
// The remainder is zero, so the candidate is not prime
is_prime = false;
break;
}
// The next factor to try. Simply
// increment the current factor by one
factor++;
}
// Display the result in the console window.
// If candidate has no integer factor, then
// the auxiliary variable is_prime still true
if ( is_prime )
{
console.log(candidate, "is prime");
}
else
{
console.log(candidate, "is not prime");
}
La dichiarazione di blocco che segue l’istruzione while
verrà eseguita ripetutamente finché la condizione factor < candidate
è vera. Verrà eseguita almeno una volta, finché inizializzeremo la variabile factor
con un valore inferiore a candidate
. La struttura if
annidata nella struttura while
valuterà se il resto di candidate
diviso per factor
è zero. Se è così, il numero candidate
non è primo e il ciclo può finire. L’istruzione break
terminerà il ciclo e l’esecuzione salterà alla prima istruzione dopo il blocco while
.
Nota che il risultato della condizione usata dall’istruzione while
deve cambiare a ogni ciclo, altrimenti l’istruzione di blocco andrà in loop “per sempre”. Nell’esempio, incrementiamo la variabile factor
— il prossimo divisore che vogliamo provare — e questo garantisce che il ciclo finisca a un certo punto.
Questa semplice implementazione di un tester di numeri primi funziona come previsto. Tuttavia, sappiamo che un numero che non è divisibile per due non sarà divisibile per nessun altro numero pari. Pertanto, potremmo semplicemente saltare i numeri pari aggiungendo un’altra istruzione if
:
while ( factor < candidate )
{
// Skip even factors bigger than two
if ( factor > 2 && factor % 2 == 0 )
{
factor++;
continue;
}
if ( candidate % factor == 0 )
{
// The remainder is zero, so the candidate is not prime
is_prime = false;
break;
}
// The next number that will divide the candidate
factor++;
}
L’istruzione continue
è simile all’istruzione break
, ma invece di finire questa iterazione del ciclo, ignorerà il resto del blocco del ciclo e inizierà una nuova iterazione. Nota che la variabile factor
è stata modificata prima dell’istruzione continue
, altrimenti il ciclo avrebbe lo stesso risultato nella prossima iterazione. Questo esempio è troppo semplice e saltare una parte del ciclo non migliorerà realmente le sue prestazioni, ma saltare le istruzioni ridondanti è molto importante quando si scrivono applicazioni efficienti.
I cicli sono così comunemente usati che esistono in molte varianti diverse. Il ciclo for
è particolarmente adatto per iterare attraverso valori sequenziali, perché ci permette di definire le regole del ciclo in una sola riga:
for ( let factor = 2; factor < candidate; factor++ )
{
// Skip even factors bigger than two
if ( factor > 2 && factor % 2 == 0 )
{
continue;
}
if ( candidate % factor == 0 )
{
// The remainder is zero, so the candidate is not prime
is_prime = false;
break;
}
}
Questo esempio produce esattamente lo stesso risultato dell’esempio precedente while
, ma la sua espressione parentetica include tre parti, separate da punto e virgola: l’inizializzazione (let factor = 2
), la condizione del ciclo (factor < candidate
), e l’espressione finale da valutare alla fine di ogni iterazione del ciclo (factor+`). Le istruzioni `continue` e `break` si applicano anche ai cicli `for`. L'espressione finale tra le parentesi (`factor+
) sarà valutata dopo l’istruzione continue
, quindi non dovrebbe essere all’interno dell’istruzione di blocco, altrimenti sarà incrementata due volte prima della prossima iterazione.
JavaScript ha tipi speciali di cicli for
per lavorare con oggetti simili ad array. Potremmo, per esempio, controllare un array di variabili invece di una sola:
// A naive prime number tester
// The array of numbers we want to evaluate
let candidates = [111, 139, 293, 327];
// Evaluates every candidate in the array
for (candidate of candidates)
{
// Auxiliary variable
let is_prime = true;
for ( let factor = 2; factor < candidate; factor++ )
{
// Skip even factors bigger than two
if ( factor > 2 && factor % 2 == 0 )
{
continue;
}
if ( candidate % factor == 0 )
{
// The remainder is zero, so the candidate is not prime
is_prime = false;
break;
}
}
// Display the result in the console window
if ( is_prime )
{
console.log(candidate, "is prime");
}
else
{
console.log(candidate, "is not prime");
}
}
L’istruzione for (candidate of candidates)
assegna un elemento dell’array candidates
alla variabile candidate
e lo usa nella dichiarazione di blocco, ripetendo il processo per ogni elemento dell’array. Non c’è bisogno di dichiarare separatamente candidate
, perché il ciclo for
lo definisce. Infine, lo stesso codice dell’esempio precedente è stato annidato in questa nuova istruzione a blocchi, ma questa volta testando ogni candidate
nell’array.
Esercizi Guidati
-
Quali valori della variabile
my_var
corrispondono alla condizionemy_var > 0 && my_var < 9
? -
Quali valori della variabile
my_var
corrispondono alla condizionemy_var > 0 && my_var < 9
? -
Quante volte il seguente ciclo
while
esegue la sua dichiarazione di blocco?let i = 0; while ( 1 ) { if ( i == 10 ) { continue; } i++; }
Esercizi Esplorativi
-
Cosa succede se l’operatore di assegnazione uguale
=
viene usato al posto dell’operatore di confronto uguale==
? -
Scrivi un frammento di codice usando la struttura di controllo
if
dove un confronto ordinario di uguaglianza restituirà true, ma un confronto di uguaglianza rigoroso no. -
Riscrivi la seguente istruzione
for
usando l’operatore logico unario NOT nella condizione del ciclo. Il risultato della condizione dovrebbe essere lo stesso.for ( let factor = 2; factor < candidate; factor++ )
-
Sulla base degli esempi di questa lezione, scrivi una struttura di controllo del loop che mostri tutti i fattori interi di un dato numero.
Sommario
Questa lezione spiega come usare le strutture di controllo nel codice JavaScript. Le strutture condizionali e i loop sono elementi essenziali di qualsiasi paradigma di programmazione, e lo sviluppo web in JavaScript non fa eccezione. La lezione passa in rassegna i seguenti concetti e procedure:
-
L’istruzione
if
e gli operatori di confronto. -
Come usare la struttura
switch
concase
,default
ebreak
. -
La differenza tra confronto ordinario e rigoroso.
-
Strutture di controllo dei cicli:
while
efor
.
Risposte agli Esercizi Guidati
-
Quali valori della variabile
my_var
corrispondono alla condizionemy_var > 0 && my_var < 9
?Solo i numeri che sono sia maggiori di 0 che minori di 9. L’operatore logico
&&
(AND) richiede che entrambi i confronti corrispondano. -
Quali valori della variabile
my_var
corrispondono alla condizionemy_var > 0 && my_var < 9
?Solo i numeri che sono sia maggiori di 0 che minori di 9. L’operatore logico
&&
(AND) richiede che entrambi i confronti corrispondano. -
Quante volte il seguente ciclo
while
esegue la sua dichiarazione di blocco?let i = 0; while ( 1 ) { if ( i == 10 ) { continue; } i++; }
La dichiarazione di blocco si ripeterà indefinitamente, poiché non è stata fornita alcuna condizione di arresto.
Risposte agli Esercizi Esplorativi
-
Cosa succede se l’operatore di assegnazione uguale
=
viene usato al posto dell’operatore di confronto uguale==
?Il valore a destra dell’operatore viene assegnato alla variabile a sinistra e il risultato viene passato al confronto, che potrebbe non essere il comportamento desiderato.
-
Scrivi un frammento di codice usando la struttura di controllo
if
dove un confronto ordinario di uguaglianza restituirà true, ma un confronto di uguaglianza rigoroso no.let a = "1"; let b = 1; if ( a == b ) { console.log("An ordinary comparison will match."); } if ( a === b ) { console.log("A strict comparison will not match."); }
-
Riscrivi la seguente istruzione
for
usando l’operatore logico unario NOT nella condizione del ciclo. Il risultato della condizione dovrebbe essere lo stesso.for ( let factor = 2; factor < candidate; factor++ )
Risposta:
for ( let factor = 2; ! (factor >= candidate); factor++ )
-
Sulla base degli esempi di questa lezione, scrivi una struttura di controllo del loop che mostri tutti i fattori interi di un dato numero.
for ( let factor = 2; factor <= my_number; factor++ ) { if ( my_number % factor == 0 ) { console.log(factor, " is an integer factor of ", my_number); } }