Strutture di controllo in JavaScript
L'importanza delle strutture di controllo nei linguaggi di programmazione risiede nel fatto che attraverso di esse l'elaboratore viene messo in condizione di prendere delle decisioni autonome.
I costrutti fondamentali del linguaggio Javascript rimangono quelli già visti in C e Java, in particolare abbiamo la selezione binaria data dall'istruzione if-else:
if(condizione){
//istruzioni-a
}else{
//istruzioni-b
}
dove viene usato il marcatore // per il commento
di una singola linea;
mentre per i commenti multilinea si usano i marcatori
/* . . . */ .
Ricordiamo che nel caso venga eseguita una singola istruzione sul ramo if
e/o sul ramo else, le parentesi graffe non sono obbligatorie.
La stessa
clausola else non è obbligatoria; cioè si può anche fare
if(condizione){
/* istruzioni-a */
}
La differenza è evidente, nel primo caso l'elaboratore esegue comunque 'qualcosa' nel secondo caso non è detto che faccia 'qualcosa' :se la condizione logica di test è falsa può anche non fare niente (e passare alle istruzioni successive).
Un esempio di if semplice (privo di else) è il seguente scritto che ottiene la radice quadrata della variabile x solo ed esclusivamente se essa contiene un valore numerico maggiore o uguale a zero.
Come si vede, per l'estrazione di radice, si fa uso dell'oggetto Math e della funzione sqrt() già vista in linguaggio Java; si può affermare che le varie funzioni matematiche hanno lo stesso identificatore (nome) in entrambi i linguaggi.
Una variante dell'esempio precedente che prevede l'uso della sintassi completa if-else ,è la seguente, dove nel caso il valore numerico della variabile x sia negativo viene mandato in output un segnale di errore.
Il costrutto if nella sua forma completa può essere sostituito da una forma più sintetica costituita dall'operatore ternario caratterizzato dalla seguente sintassi:
(condizione) ? se_vero : se_falso; come è possibile notare nel seguente listato:
Un costrutto comune in tutta la programmazione dei calcolatori è l' if-else-if : una struttura a scala che ha la seguente forma
if (condizione_1) {istruzioni_a;}
else if (condizione_2){istruzioni_b;}
else if (condizione_3){istruzioni_c;}
. . .
else {istruzioni_n;}
Il calcolatore inizia la valutazione delle espressioni condizionali dall'alto
verso il basso ed esegue la prima che viene verificata (true) abbandonando,
dopo aver eseguito il blocco di codice corrispondente, la catena di if.
Se non si verifica nessuna delle condizioni, viene eseguito l' else finale,
che spesso ha il significato concettuale di condizione di default.
Se non è presente l'ultimo else, qualora non si sia verificata nessuna delle
condizioni, non viene intrapresa nessuna azione.
Nell'esempio che segue viene fatto uso di una struttura if-else-if per determinare
se abbiamo indovinato un numero casuale da 0 a 9 che il computer ha 'pensato'.
Sebbene il costrutto if-else-if consenta di realizzare
dei test multipli, è da considerare una struttura poco elegante che può
risultare di difficile lettura.
Per queste ragioni, quando il test multiplo viene eseguito su dei valori
costanti è conveniente usare la struttura switch.
In questo costrutto il valore di una variabile viene confrontato con una
lista di costanti; quando si verifica una uguaglianza, si esegue il blocco
di istruzioni corrispondenti:
switch(variabile){
case costante_1 : istruzioni_a; break;
case costante_2 : istruzioni_b; break;
case costante_3 : istruzioni_c; break;
. . .
default: istruzioni_n;
}
in questa sintassi, la parte default è opzionale,
e se è presente viene eseguita nel caso in cui non si verifichi alcuna corrispondenza.
Se non è presente la clausola default e non ci sono
corrispondenze, non viene eseguita nessuna azione.
Quando viene trovata una corrispondenza, sono eseguite le istruzioni associate
al case fino all'istruzione break.
Nonostante l'eleganza formale, i test del costrutto switch possono solo
verificare l'uguaglianza a differenza di quelli dell' if-else-if
che possono verificare condizioni di qualsiasi tipo.
Con tutta probabilità l'istruzione switch() è stata
introdotta per soddisfare alcuni bisogni primari dell'uomo, quali l'accesso
alle funzioni di un bancomat:
Le istruzioni break non sono indispensabili all'interno
di uno switch, in quanto nel caso siano assenti l'esecuzione
del programma prosegue nelle istruzioni relative al case
successivo, fino a quando non viene incontrato il primo break o la fine
della struttura di controllo.
I case possono essere considerati come delle etichette
che indicano i punti di entrata nel codice, mentre i punti di uscita sono
i break e la fine del costrutto.
Cicli iterativi
I cicli indicano al calcolatore di eseguire un insieme di istruzioni fino a quando non è verificata una determinata situazione. I tipi di ciclo permessi in JS sono gli stessi presenti negli altri linguaggi di programmazione; si tratta del ciclo while, del ciclo do-while e del ciclo for.
La struttura di controllo ciclica consente di tornare ad un punto precedente del programma e ripetere un blocco di istruzioni per lo stato attuale, il tipo di ciclo più semplice da scrivere è il ciclo while:
while(condizione){
/* istruzioni */
}
Nel seguente esempio, la variabile n viene inizializzata a 0, poi entra in un ciclo while dove viene stampata a video e viene successivamente incrementata di 1 (n++) il ciclo continua finchè è vera (true) la condizione logica espressa tra le parentesi dell'istruzione while.
Il ciclo, viene dunque ripetuto, fin tanto che rimane vera la condizione
specificata.
Quando la condizione diventa falsa, l'esecuzione procede dalla prima istruzione
successiva al ciclo (nel nostro caso il programma termina).
Il fatto che la condizione logica sia verificata
all'inizio del loop, comporta l'eventualità che il ciclo possa anche non
essere eseguito nemmeno una volta.
A differenza del ciclo while che verifica la condizione all'inizio del loop, il ciclo do-while esegue la verifica alla fine, con la conseguenza che il do-while viene eseguito almeno una volta
do{
/* istruzioni */
}while(condizione);
In questo caso usiamo il costrutto do-while per acquisire 5 numeri da tastiera per restituirne la somma. Abbiamo bisogno di una variabile contatore i inizializzata a 0 come la variabile sum che sarà usata come accumulatore.
Per l'acquisizione da tastiera viene usata la funzione standard prompt()
che serve per impostare una domanda aperta e consente di usare una finestra
di dialogo per l'inserimento del valore.
Per definizione tutti i linguaggi di programmazione, da tastiera, acquisiscono
esclusivamente stringhe; ecco il motivo del perchè l'istruzione prompt()
viene incapsulata come argomento nella funzione parseInt();
che ha il solo scopo di convertire (se possibile) l'input acquisito dalla
funzione prompt() in un numero intero.
La funzione isNaN() è una funzione standard JS che
restituisce true solo se l'argomento passato è NaN (Not a Number=non un
numero) in questo caso la sua forma negata !isNaN(n) sarà
true solo se n rappresenta effettivamente un numero.
La variabile contatore i, parte da 0 e compie 5 iterazioni
(da 0 a 4 inclusi). Ad ogni iterazione la variabile sum
viene incrementata del valore del numero n inserito
da tastiera.
In ogni caso, il seguente esempio, mette in evidenza la differenza fondamentale tra i due costrutti while e do-while
All'interno della pagina inseriamo due tag, il primo con identificatore
id="W" per il ciclo while, il secondo con
indentificatore id="DW" per il do-while;
nello scritto che segue, la variabile n viene posta
a 15 ma l'immediato controllo del while(n<10)n++;
impedisce ad n di incrementarsi perchè la condizione
logica è da subito falsa, quindi nel tag del while
il valore di n viene stampato a 15.
Poi per sicurezza reimpostiamo il valore di n a 15
e tentiamo di incrementare n attraverso il costrutto do{n++;}while(n<10);
prima di essere espulsa dal ciclo la n viene incrementata
di 1; questo perchè il test di validità, in questo caso viene eseguito alla
fine dello stesso.
Sia il costrutto while che il do-while vengono usati quando a priori non sappiamo quante iterazioni si devono fare, ma quando questo numero è noto, si può usare il ciclo for che in tutti linguaggi di programmazione procedurale appare con la sintassi:
for(inizalizzazione; condizione; incremento) {
/* istruzioni */
}
L'inizializzazione è, nella sua forma più semplice, un istruzione di assegnamento
con la quale si posiziona il valore iniziale della variabile di controllo
del ciclo.
La condizione è una espressione relazionale usata per valutare la variabile
di controllo al fine di determinare il momento di uscita dal ciclo; l'esecuzione
procede fintanto che la condizione è vera, mentre quando diviene falsa l'esecuzione
precede con le istruzioni successive al for.
L'incremento definisce il modo in cui la variabile di controllo cambia il
suo valore ad ogni ripetizione di ciclo.
Queste tre parti devono essere separate da un punto e virgola.
In questo caso il for eseguirà 8 iterazioni (dettate dalla costante n) da con la variabile di controllo i che varia da 0 a 7 inclusi, ad ogni esecuzione la stessa variabile viene stampata in output perchè questo è scritto nel corpo del ciclo.
E' possibile predisporre dei costrutti for che prevedano
l'uscita prematura dal ciclo.
Nel seguente esempio usiamo un for per acquisire
una sequenza di 5 numeri interi di cui poi vogliamo calcolare la somma.
All'interno del corpo del for è stato inserito un
if che valuta se il valore inserito da tastiera può
essere assimilato ad un numero.
Se si cerca di inserire una stringa qualsiasi, il ciclo si interrompe stampando
il valore della somma fin lì calcolata.
Tag di selezione
Oltre ai tag di input per la casella di testo, indicata attraverso la forma
<input type="text" >
ed al pulsante di azione
<input type="button" >
è possibile realizzare in HTML altri tipi di elementi, in particolar modo oggetti riservati alla selezione, quali la casella combinata a discesa definita dai tag select/option nel seguente modo:
<select id="sel">
<option value="A" >Opzione 1
<option value="B" >Opzione 2
<option selected value="C">Opzione 3
</select>
In JavaScript è poi possibile determinare quale elemento sia stato selezionato
Notiamo come sia possibile usare lo specificatore selected
per definire quale item può essere selezionato in via preliminare; è inoltre
possibile, accedere all'attributo di un singolo item, leggendo il suo valore,
attraverso la proprietà .value, oppure è possibile
accedere all'indice dell'item selezionato, attraverso l'attributo
.selectedIndex, mentre la voce riportata esplicitamente in elenco
può essere acquisita leggendo la proprietà .options[indice].text,
che può essere usata a patto di conoscere l'indice dell'elemento selezionato.
A tal proposito, si deve notare che il primo item dell'elenco ha sempre
indice 0 (zero) come nel caso dei vettori (array) già visti negli
altri linguaggi di programmazione.
Un altro strumento di selezione che può essere usato è la casella di spunta
(checkbox). La checkbox è dotata dell'attributo .checked
che contiene un valore booleano (true/false) in grado di rivelare se la
casella in questione è stata selezionata oppure no.
Il seguente esempio fa uso di questa proprietà ed è stato organizzato in
modo di gestire due caselle di testo per mutua esclusione.
Stavolta un gestore di eventi onclick è stato associato a ciascuna casella,
in modo da chiamare due funzioni che resettano la casella opposta a quella
appena selezionata. In assenza di queste funzioni sarebbe possibile selezionare
anche più checkbox simultaneamente.
In alternativa alle checkbox, sarebbe possibile utilizzare i pulsanti radio;
ma per fare questo è sufficiente sostituire il tipo specificato; cioè scrivere
<input type="radio". . . al posto di <input type="checkbox" . . .
Un altro controllo molto interessante è range : una barra a scorrimento in grado di erogare valori numerici all'interno di un predeterminato intervallo.
Nel seguente esempio viene implementato il calcolo del montante di un dato capitale in funzione del numero di anni impiegato, secondo la formula M=C·(1+i)n.
Dove M è il montante, C è il capitale, i è l'interesse ed n il numero di anni.