29 funzioni – parametri in n variabili, opzionali e rest
n parametri
approfondiamo il discorso sui parametri
writeln( somma() ); writeln( somma(1) ); writeln( somma(10,20) ); writeln( somma(1,2,3,4,5,6,7) );
apparentemente abbiamo 4 versioni differenti nel passare i parametri alla funzione somma. In C++ e altri linguaggi che supportano questo meccanismo dell’esempio la procedura è chiamata overload di una funzione. In js la funzione somma è una sola ed è stata strutturata in modo tale da usare la lista dei parametri, argomento insito in ogni funzione
//lista dei parametri per gestirne un numero variabile function somma() { var totale = 0; for(var i=0; i<arguments.length; i++) {totale += arguments[i];} return totale; }
Questa lista dei parametri ha un nome predefinito, si chiama arguments , che è un oggetto predefinito (usabile come un array), in cui possiamo accedere alla proprietà arguments.length che corrisponde agli argomenti in arrivo, che possiamo iterare con un ciclo for
writeln( somma() ); // corrisponderà a length == 0
invece
writeln( somma(10,20) ); //length == 2 , arguments[0] = 10 , arguments[1] = 20
e così anche per gli altri argomenti eventualmente passati.
Nella funzione somma il passaggio di n argomenti è stato premeditato fin dall’inizio ed è di facile gestione, in quanto basta passare dei numeri per fare la somma. A volte ci troviamo nella necessità di dover aggiungere un diverso parametro, poi magari nel tempo un altro, non previsti fin dall’inizio, vorrebbe dire che tutto il vecchio codice, che utilizza meno parametri, andrebbe riscritto per adattarlo.
Oppure, situazione intermedia, noi sappiamo fin dall’inizio che la funzione prevede 5 o 6 parametri, ma nella situazione normale se ne utilizzano soltanto 2 e in casi particolari anche gli altri, l’ideale sarebbe non doverli far specificare tutti, inserendo dei parametri non obbligatori.
Parametri opzionali
Da ECMAScript 6 (o ES6 ) è stato introdotto nel js il concetto di parametri opzionali .
writeln("La pazienza é la virtú dei forti");
Questa forma è quella a noi familiare, con la quale stampo una classica stringa (1 parametro).
Pensiamo invece alla funzione writeln come capace di gestire all’occorrenza anche le citazioni, scritte tra virgolette angolari o basse o doppie frecce.
Senza cambiare tutto il codice ho semplicemente aggiunto alla funzione un parametro opzionale, che adesso andrò ad utilizzare:
writeln("La pazienza é la virtú dei forti",true);
Nella logica della funzione il secondo parametro (quello che decide se è una citazione) è impostato di default a false e non mettendo nulla il messaggio sarà stampato normalmente, se è una citazione, metterò il secondo parametro a true e il messaggio sarà stampato come citazione.
Ecco la funzione
function writeln(messaggio, citazione=false) //signature (firma) { if (citazione) {messaggio = "«" + messaggio + "»"; } document.write(messaggio+br); }
citazione=false è il mio valore opzionale e tale opzionali è data dal fatto che assegno un valore di default al parametro che verrà utilizzato in automatico qualora non sarà specificato.
if (citazione) {messaggio = "«" + messaggio + "»"; }
se citazione è true ( if(citazione) )aggiungi le freccette al messaggio
Parametri rest
un’altra forma introdotta da ES6 permette di inserire i parametri previsti in modo normale e di generalizzare con i restanti parametri sotto forma di una array
function calcolo(a, b, ...ilRestoDeiParametri)
In questo caso sono chiaramente indicati 2 parametri (a e b), ma potrebbe essere anche zero parametri e gli eventuali restanti parametri saranno memorizzati nell’array ilRestoDeiParametri. In altre parole si lascia libera il resto dei parametri. Per includere questa forma si usano i tre punti … seguiti dal nome dell’array
function calcolo(a, b, ...ilRestoDeiParametri) { totale = a*b; ilRestoDeiParametri.forEach( controlla_e_somma, this ); return totale; }
Questa è la funzione calcolo completa, ma prima vediamo la chiamata:
writeln( calcolo(2,3,45,100) );
i primi 2 parametri sono previsti (a e b ), poi potrebbero essere 0 o altri 50.
Il terzo e quarto parametro con i valori 45 e 100 verranno veicolati alla funzione calcolo sotto forma di un array contenete i 2 valori:
ilRestoDeiParametri[0] == 45 ilRestoDeiParametri[1] == 100
approfondimento
La tecnica appena vista è un miglioramento rispetto alla possibilità di usare arguments, perché arguments non è un array e quindi non ci permette di usare una serie di funzioni predefinite per gli array, come nel nostro esempio della funzione calcolo, dove dico
ilRestoDeiParametri.forEach( controlla_e_somma, this ); return totale;
Se ilRestoDeiParametri è un array usa la particolare funzione per gli array forEach che dice per ogni elemento dell’array usa la funzione indicata (controlla_e_somma) che andremo poi a costruire. Il secondo parametro inserito in forEach è un puntatore speciale chiamato this che fa riferimento alle variabili d’ambiente della funzione calcolo e permettere a controlla_e_somma di modificare il valore della variabile totale (vedremo specificatamente this più avanti)
Vediamo la funzione controlla_e_somma che restituirà il valore dell’elemento, la posizione nell’array e l’array stesso
function controlla_e_somma(valore, indice, array) { if(valore<100) {this.totale += valore;} }
se il valore è minore di 100 dell’ elemento passato dal forEach che ha estratto a sua volta dall’array ilRestoDeiParametri, alla variabile totale aggiungo il valore. Interessante come la funzione possa accedere alla variabile ad essa esterna, grazie al puntatore this.
Infatti col 45 la funzione restituirà 51 (a * b + 45), mentre il 100 supera la soglia e non verrà utilizzato.
La funzione controlla_e_somma non riceve solo il valore dall’array, ma anche l’indice del valore che ci potrebbe servire per fare dei filtri, in base all posizione, o ulteriori calcoli , inoltre riceve anche il riferimento all’intero array. I nomi dei parametri (valore, indice, array) sono nomi di fantasia.
Arguments comunque può venire utile quando ho bisogno di avere a disposizione tutti i parametri, rest invece contiene solo i restanti ( a e b non ci sono) . Inoltre arguments può contenere parametri aggiuntivi non propri degli array.