Il linguaggio Javascript - University of L`Aquila

Transcript

Il linguaggio Javascript - University of L`Aquila
Javascript
Dispense per il corso di Ingegneria del Web
Revisione 05/11
Giuseppe Della Penna ([email protected])
Dipartimento di Informatica
Università degli studi dell'Aquila
Corso di Ingegneria del Web
Javascript: Tool di sviluppo
Il Linguaggio Javascript
Javascript è un linguaggio di scripting, cioè è progettato per lavorare all'interno di un host, ad
esempio un browser, per automatizzarne e gestirne alcune funzionalità.
Nonostante il nome, non ha nulla a che vedere con Java, ma è invece l'implementazione più
riuscita
e
diffusa
dello
standard
ECMAScript
(http://www.ecmainternational.org/publications/standards/Ecma-262.htm), dovuta inizialmente a Netscape. Da
notare che la piattaforma Microsoft possiede un proprio linguaggio di scripting, noto come JScript,
che è anch'esso un'implementazione di ECMAScript. In ogni caso, Javascript è l'unico linguaggio di
scripting supportato da tutti i browser moderni.
Imparare a usare bene Javascript è complesso, in quanto il linguaggio è molto particolare in alcuni
suoi aspetti. Tuttavia, la versatilità di Javascript lo rende uno strumento unico ed eccezionale per
realizzare applicazioni web di grande impatto. Basti pensare alle applicazioni realizzate da Google
Apps, che fanno larghissimo uso di questo linguaggio per programmare sistemi la cui logica lato
client li rende molto simili alle normali applicazioni desktop. L'avvento della tecnologia AJAX, poi,
ha reso Javascript ancor più famoso.
L'utilità di Javascript non si ferma alla programmazione del browser: infatti, Javascript può essere incorporato in
qualsiasi applicazione come linguaggio di scripting, ad esempio è possibile incorporare Javascript in qualsiasi
applicazione Java usando la libreria Rhino (http://www.mozilla.org/rhino/).
Come ultimo esempio delle potenzialità di Javascript... notate che quasi tutte le funzionalità
estese di Firefox sono programmate con Javascript stesso!
Un unico avvertimento va fatto, prima di cominciare a programmare: resistete sempre alla
tentazione di inserire script inutili nella vostra pagina, e di realizzare con Javascript funzionalità
che potrebbero essere ottenute con un uso accorto di HTML e CSS (ad esempio molti tipi di
menu). Javascript può essere un enorme ostacolo all'accessibilità piena della vostra applicazione,
sopratutto per i soliti problemi di compatibilità crossbrowser, che in Javascript sono sempre
presenti, e che possono rendere un'applicazione totalmente basata sugli script inservibile sul
prossimo browser (per non parlare dei precedenti!). Prevedete sempre la possibilità che le vostre
pagine siano aperte da un browser in cui Javascript non funziona o è disattivato, e verificate se in
questo caso i contenuti restano comunque accessibili!
Tool di sviluppo
Javascript si può scrivere con qualsiasi buon editor di testo. Netbeans, che usiamo già per lo
sviluppo Java, dispone di un ottimo editor assistito per questo linguaggio.
Tuttavia il tool indispensabile per lo sviluppo e il debugging di Javascript è l'add-on di Firefox "Firebug"
(http://getfirebug.com/).
Installatelo, e avrete una console da cui
•
•
•
provare codice Javascript generico
eseguire interattivamente Javascript sulle vostre pagine
visionare gli errori ed eseguire debugging degli script presenti sulle pagine web
Revisione 05/11
Pagina 2/27
Corso di Ingegneria del Web
Javascript: Usare Javascript nelle pagine HTML
e inoltre
•
•
•
analizzare la struttura delle pagine web
analizzare e modificare gli stili associati agli elementi delle pagine web
analizzare e ottimizzare il traffico di rete effettuato dalla vostra applicazione web
Date un'occhiata a http://getfirebug.com/doc/enablement/enablement1.4.html per capire come attivare
Firebug. Leggete quindi http://getfirebug.com/cl.html per capire meglio come funziona la linea di comando
immediata Javascript, da cui provare i vostri esempi. Infine, leggete http://getfirebug.com/js.html per capire
come Firebug può aiutarvi in generale a gestire i vostri script.
Usare Firebug è semplice: una volta installato, cliccate sul piccolo simbolo che si aggiungerà sulla
statusbar del browser per aprire la console. Da qui potrete vedere tutti i messaggi di errore
generati dai vostri script. Se volte eseguire del codice di esempio, come quello proposto in queste
lezioni, potete scriverlo in maniera diretta nella riga di input presente in basso, e vederne i risultati
direttamente sulla console.
Usare Javascript nelle pagine HTML
Per incorporare uno script in una pagina HTML, si utilizza il tag <script> con attributo type
impostato al valore "text/javascript". Questo tag (si veda la documentazione di HTML) può essere
inserito sia nella <head> del documento, sia all'interno del <body>. Discuteremo più avanti il
significato di questi due approcci, tuttavia, quando possibile, è consigliabile caricare gli script
sempre nella <head>.
Visto che il codice Javascript contiene spesso caratteri HTML riservati come ">" o "&", si rende
necessario usare la direttiva XML CDATA per isolare lo script indicando che il suo contenuto è
testo semplice. Purtroppo, però, alcuni browser, anche moderni, non comprendono la direttiva
CDATA, ovvero assumono un CDATA implicito all'interno del tag <script>. Per adattarsi a tutte
queste varianti, il codice corretto per l'inserimento di uno script all'interno di una pagina web è il
seguente
<script type="text/javascript>
//<![CDATA[
...
//]]>
</script>
In questo modo, gli script che non comprendono il significato speciale di CDATA lo ignoreranno in
quanto inserito in un commento Javascript (righe che iniziano con "//"), mentre gli altri lo
interpreteranno correttamente. Da notare che, per compatibilità con i browser più datati, il codice
all'interno dello script viene a volte posto anche tra indicatori di commento HTML (<!-- -->).
Questa procedura è ormai inutile, in quanto tutti i browser delle ultime generazioni conoscono il
tag script, anche se a volte non sono in grado di interpretarlo.
E' anche possibile caricare script esterni, lasciando il tag <script> vuoto e specificando la URI
dello script tramite l'attributo src. Anche in questo caso,per compatibilità con alcuni browser, è
opportuno non scrivere mai il tag <script> vuoto nella forma abbreviata, ma inserire sempre il tag
di chiusura in maniera esplicita, come nell'esempio che segue
<script type="text/javascript" src="..."/> <!-- NON SICURO -->
<script type="text/javascript" src="..."></script> <!-- SICURO -->
Revisione 05/11
Pagina 3/27
Corso di Ingegneria del Web
Javascript: Tipi di dato Javascript
Si possono inserire e importare più script diversi all'interno dello stesso documento, usando più
tag <script>. Esistono inoltre alcuni attributi HTML in cui si può incorporare del codice, cioè
•
•
gli attributi per la gestione degli eventi, come onclick, possono contenere frammenti di
codice (ma non dichiarazioni), da eseguire al verificarsi dell'evento.
l'attributo href del tag <a> può fare riferimento a una funzione Javascript con la sintassi:
"Javascript:nomefunzione(argomenti)". In questo caso, il click del link eseguirà la chiamata
alla funzione.
Come regola generale, gli script andrebbero sempre posti in file esterni e importati usando la
seconda forma dell'elemento <script>. Inoltre, l'assegnazione di codice agli attributi degli elementi
HTML dovrebbe essere realizzata dal codice stesso, e non apparire tra il markup, come vedremo
più avanti. Infine, l'uso di Javascript nell'attributo href del tag <a> andrebbe limitato, utilizzando in
sua sostituzione l'evento onclick dello stesso elemento. Tutto questo per mantenere una rigorosa
separazione tra codice HTML e Javascript.
Esecuzione degli script nelle pagine HTML
Come già accennato, il tag <script> può apparire sia nella <head>, dove viene normalmente posto
per la maggior parte degli script, sia in qualunque punto del <body>. Ogni script può utilizzare
liberamente funzioni e variabili dichiarate in altri script inseriti nella stessa pagina.
Nello scegliere il punto in cui inserire uno script, bisogna tener presente che tutte le funzioni e le
variabili dichiarate negli script diventano disponibili (quindi possono essere usate e chiamate) non
appena il parser analizza il punto della pagina in cui sono dichiarate. Inoltre, se uno script contiene
codice immediato, cioè scritto al di fuori di funzioni, questo viene eseguito non appena il parser
analizza il punto della pagina in cui il codice compare.
Inserire uno script in un certo punto del <body> serve quindi solo ad assicurarsi che esso venga
valutato solo dopo che l'elemento HTML a cui si riferisce è stato caricato (assumendo quindi di
porre lo script dopo l'elemento in questione). Tuttavia, invece che utilizzare questa tecnica, è
spesso più pratico (nonché più "pulito", mantenendo HTML e Javscript maggiormente separati)
eseguire qualsiasi script quando tutta la pagina HTML è stata caricata, e quindi tutto il contenuto
del documento è disponibile per analisi e manipolazioni. Questo può essere realizzato utilizzando
l'evento onload dell'oggetto window. Chiariremo più tardi il significato di questo codice, tuttavia
per ora consideriamo il frammento che segue
window.onload = function() { ... }
inserendo questo frammento tra gli script nella <head> della nostra pagina, ci assicureremo che
tutto il codice all'interno delle graffe sia eseguito quando il documento HTML è completamente
caricato. Questo è quindi il luogo adatto per eseguire qualsiasi inizializzazione degli script
contenuti nella pagina, modifica iniziale al documento stesso, ecc.
Tipi di dato Javascript
Javascript gestisce cinque diversi tipi di dato, che illustriamo qui di seguito. Da notare che non
esiste tra i tipi base l'array, in quanto viene trattato come un particolare oggetto, e verrà illustrato
più avanti.
Revisione 05/11
Pagina 4/27
Corso di Ingegneria del Web
Javascript: Variabili e Dichiarazione
Numeri
Non c'è distinzione tra interi e reali. Sono costanti numeriche tutte le espressioni che
rappresentano un numero valido, con e senza virgola.
Le funzioni parseInt e parseFloat possono essere usate per convertire stringhe in numeri.
Stringhe
Le stringhe sono particolari oggetti Javascript. Possono essere create implicitamente, attraverso
una costante di tipo stringa, o esplicitamente tramite il costruttore dell'oggetto String. Sono
costanti di tipo stringa i valori racchiusi tra virgolette (singole o doppie).
Tutti i tipi di dato vengono automaticamente convertiti in stringa quando si trovano in un
contesto che richieda la presenza di una stringa (ad esempio, nelle istruzioni di stampa, o quando
vengono concatenati a un'altra stringa).
Oggetti
Gli oggetti sono un tipo di dato molto comune in Javascript, che tratteremo in dettaglio più
avanti. Le variabili di tipo oggetto contengono in effetti dei riferimenti ad oggetti (come in Java).
Più variabili possono quindi fare riferimento allo stesso oggetto.
In Javascript il tipo oggetto è molto diverso da quello usato nei linguaggi di programmazione
object-oriented. Non bisogna quindi pensare gli oggetti Javascript come veri oggetti, ma piuttosto
come "contenitori di informazioni e funzioni" con un comportamento simile a quello dei veri
oggetti.
Null
Il tipo nullo ha un unico valore, null.
Booleani
Le costanti boooeane sono true e false. Tutti gli altri tipi di dato possono venire convertiti, se
necessario, in valori booleani in base alle regole che seguono:
•
•
•
•
Se l'espressione ha un valore numerico diverso da zero è true.
Se l'espressione ha un valore stringa non vuoto è true.
Se l'espressione ha un valore oggetto è true.
In tutti gli altri casi (numerico zero, stringa vuota, valore undefined o null) l'espressione è
false.
Variabili e Dichiarazione
Le variabili Javascript sono identificate da sequenze alfanumeriche il cui primo carattere deve
essere alfabetico. Le variabili non hanno un tipo: questo viene dedotto automaticamente dal
valore assegnato alla variabile stessa (ad esempio come in PHP), e può cambiare nel tempo.
Revisione 05/11
Pagina 5/27
Corso di Ingegneria del Web
Javascript: Operatori
Prima di utilizzare una variabile, è opportuno dichiararla utilizzando il costrutto var. Come in tutti
i linguaggi di programmazione, anche in Javascript esiste il concetto di visibilità di una variabile. Le
variabili globali sono visibili a tutto il codice, mentre quelle locali sono visibili solo all'interno del
blocco (di codice) in cui sono dichiarate. Sono variabili globali tutte quelle dichiarate al di fuori
delle funzioni. Inoltre, se si assegna un valore a una variabile non dichiarata, Javascript la crea
automaticamente come variabile globale, indipendentemente dal codice all'interno del quale
viene utilizzata: per questo motivo è fortemente sconsigliato usare variabili senza dichiararle.
Il valore iniziale di una variabile è sempre lo speciale valore undefined. E' tuttavia possibile
inizializzare la variabile inserendo un'assegnazione all'interno della sua dichiarazione. Vediamo
qualche esempio.
/* DICHIARAZIONI GLOBALI */ var x;
//x è una variabile globale di tipo indefinito e con valore undefined
var o = new Object();
//o è una variabile globale di tipo Object (vuota)
var s = "pluto";
//s è una variabile globale di tipo String con valore "pluto"
var n = 3;
//n è una variabile globale di tipo Number con valore 3
m = n;
//m è una variabile globale di tipo Number con valore 3
t = "paperino";
//t è una variabile globale di tipo String con valore "paperino"
u = v;
//u è una variabile globale con valore undefined (in quanto v non è a sua
volta definita)
var b = (3>2)
//b è una variabile globale Boolean con valore true
function f() {var x; }
/* la variabile x è una variabile locale alla funzione f, e sovrascrive
(rende invisibile) l'altra variabile x dichiarata globalmente */
Se si cerca di leggere il valore di una variabile mai dichiarata né assegnata, questo risulterà
undefined. Da notare che la lettura di una variabile non ne provoca la dichiarazione automatica,
come invece avviene con l'assegnamento.
Operatori
Gli operatori si applicano a variabili e costanti dei tipi di base Javascript per eseguire operazioni
elementari, come quelle aritmetiche. Vediamo ora una lista commentata dei principali operatori
presenti nel linguaggio.
•
•
•
+ (somma)
Oltre che a numeri, può essere applicata a stringhe, nel qual caso diventa l'operatore di
concatenazione. Se in una somma almeno un operando è una stringa, gli altri vengono
convertiti anch'essi in stringhe.
- (differenza), / (quoziente), * (prodotto), % (modulo)
= assegnamento, +=, -= (assegnamento con somma/differenza)
Gli assegnamenti con somma/differenza hanno la stessa semantica dei loro corrispondenti
in C o Java. L'assegnamento con somma può essere applicato anche a stringhe,
esattamente come l'operatore di somma.
Revisione 05/11
Pagina 6/27
Corso di Ingegneria del Web
•
•
•
•
•
•
•
•
Javascript: Operatori
++ (incremento), -- (decremento)
Hanno la stessa semantica dei loro corrispondenti in C o Java.
>> (shift right), << (shift left), & (and), | (or), ^ (xor), ~ (not)
Effettuano operazioni bit-a-bit tra operandi numerici (non si tratta di operatori logici: non
confondeteli con i seguenti!)
&& (and), || (or), ! (not)
Effettuano le comuni operazioni booleane and, or e not.
in (appartenenza)
Può essere applicato a oggetti o array (operando destro), per controllare se contengono se
la proprietà o l'indice dati (operando sinistro). Si vedano gli esempi a seguire.
> (maggiore), < (minore), >= (maggiore o uguale), <= (minore o uguale), == (uguale), != (
diverso)
Funzioni di confronto tra valori numerici. Funzionano anche con le stringhe, per le quali si
considera l'ordinamento lessicografico.
typeof(...) (controllo tipo)
Restituisce una stringa contenente il nome del tipo del suo argomento. Utile per capire che
tipo ha dedotto Javascript per una certa espressione, o per verificare che un argomento sia
del tipo giusto.
void(...) (statement nullo)
Esegue il codice passato come argomento, ma non restituisce l'eventuale valore di ritorno.
Usato solo in casi molto particolari (si veda l'esempio a seguire).
eval(...) (valutazione script)
Esegue lo script passato nell'argomento stringa e restituisce il suo valore. Utilissimo per
costruire dinamicamente un'espressione Javascript sotto forma di stringa e poi eseguirla.
Vediamo qualche esempio che coinvolga questi operatori.
var s = "tre " + 2; //s è la stringa "tre 2"
s += "uno";
//s è la stringa "tre 2 uno"
s > "ciao";
//l'espressione vale true, in quanto il valore di s è lessicograficamente
successivo a "ciao"
typeof(s);
//restituisce "string"
var o = {pippo: 1};
//questa espressione (che descriveremo più avanti) crea un oggetto con una
proprietà "pippo" impostata a 1
("pippo" in o);
//l'espressione vale true, in quanto pippo è una proprietà di o
void(0);
//statement nullo
void(f(x));
//esegue f(x) ed ignora il suo valore di ritorno
eval("f(x)");
//esegue lo script, chiamando f(x) e restituendo il valore di ritorno
della chiamata
eval("3+1");
//restituisce 4
eval("var s = 1");
//dichiara globalmente la variabile s e le assegna il valore 1.
Accade a volte di dover disabilitare l'azione di default di un collegamento <a>, ad esempio perchè
al suo posto vogliamo semplicemente chiamare uno script dichiarato tramite l'attributo onclick
Revisione 05/11
Pagina 7/27
Corso di Ingegneria del Web
Javascript: Strutture di Controllo: Esecuzione condizionale
dello stesso elemento. Per ottenere un collegamento "nullo" si usa spesso il valore "#" come href
del tag <a>, tuttavia questo, soprattutto con certi browser, può comportare a uno scroll verticale
della pagina. Il valore di href più corretto per disabilitare un link è invece la stringa
"Javascript:void(0)".
Con Javascript si può realizzare anche codice polimorfo, che accetta e gestisce (magari in maniera
diversa) tipi diversi per le stesse variabili. E' sufficiente infatti testare con l'operatore typeof il tipo
di queste variabili e procedere di conseguenza.
/* vogliamo poter passare a un codice un array di numeri. Tuttavia, se
l'array contiene un solo numero, è ammissibile che l'utente lo passi
direttamente */
if (typeof(v)=='number') v = [v];
//converte v in un array da un elemento
//il codice che segue sa gestire solo array di numeri
Strutture di Controllo: Esecuzione condizionale
Javascript dispone del costrutto if con la stessa sintassi di Java, cioè
if (guardia) {
...
} else {
...
}
Ad esempio:
var s = "valore";
var b = 0;
//costrutto if con condizione di tipo "misto"
if (s && b > 0) { s = "ok" } else { b = 1; }
La guardia può essere qualsiasi espressione valida, e viene convertita in valore booleano secondo
le regole viste sopra. Questo metodo di conversione rende possibili alcune utilissime operazioni
come la seguente:
if (v) {...}
//esegue il codice solo se v è definita e ha un valore non nullo
è possibile usare questo statement per eseguire condizionalmente del codice solo se una
variabile o una funzione sono disponibili. Infatti, se un identificatore non è definito, il suo valore
undefined è convertito in false, mentre in tutti gli altri casi diventerà true, a meno che la variabile
non rappresenti una stringa vuota o un valore zero o nullo. Se si vuole comprendere anche queste
situazioni, è più opportuno usare l'espressione di test che segue, che utilizza il costrutto typeof:
if (typeof(v)!='undefined') {...} //esegue il codice solo se v è definita
Poichè Javascript è un linguaggio estremamente estendibile, e le sue librerie di base sono
soggette a variazioni anche notevoli tra le varie implementazioni, testare se una funzione esiste
prima di usarla può essere un ottimo primo passo per realizzare script crossbrowser. Infatti, a
seconda del browser, spesso le stesse informazioni sono accessibili tramite metodi o proprietà con
nomi e sintassi differenti. Tuttavia, potendone testare la presenza nel modo appena visto, è molto
semplice capire quali proprietà sono presenti su ciascuna piattaforma.
Javascript dispone inoltre del costrutto switch con la stessa sintassi di Java, cioè
Revisione 05/11
Pagina 8/27
Corso di Ingegneria del Web
Javascript: Strutture di Controllo: Loops
switch (espressione) {
case valore1:
...
case valore2:
...
default:
...
}
L'espressione viene valutata e confrontata con i valori dei diversi case. Vengono quindi eseguite le
istruzioni a partire dal primo case con lo stesso valore dell'espressione. Se nessun case è
selezionato, vengono eseguite le istruzioni del default, se presenti. Se si desidera limitare
l'esecuzione a un gruppo di istruzioni, è necessario introdurre la parola chiave break. Ecco un
esempio:
var s = "valore";
switch (s) {
case "ok":
...
break; //questo case finisce qui
case "error": //questo case continua sul default
...
default:
...
}
Strutture di Controllo: Loops
Javascript dispone dei costrutti di ciclo for, while e do...while, con la stessa sintassi di Java:
for (inizializzazione; condizione; aggiornamento) {
corpo
}
while(condizione) {
corpo
}
do {
corpo
} while(condizione)
Nel ciclo for vengono eseguite le istruzioni di inizializzazione, quindi se la condizione è vera viene
eseguito il corpo dell'istruzione e di seguito le istruzioni di aggiornamento. Se la condizione è
ancora vera il ciclo continua. Nel ciclo while il corpo viene eseguito se e finché la condizione è vera.
Nel ciclo do...while il corpo viene eseguito almeno una volta, in quanto la condizione è testata al
termine della sua esecuzione.
Nel corpo dei loop è possibile usare le parole chiave break e continue rispettivamente per
interromperne l'esecuzione o per saltare direttamente al ciclo successivo. Vediamo qualche
semplice esempio.
var i = 0;
//ciclo for standard
for (i=0; i<10; ++i) {
j=j+1;
}
Revisione 05/11
Pagina 9/27
Corso di Ingegneria del Web
Javascript: Funzioni
//ciclo while
while(i>0) {
i=i-1;
}
//ciclo do
do {
i=i-1;
} while(i>0);
Il loop for...in
In Javascript esiste anche un'interessante variante del loop for, simile ai costrutti foreach che
sono presenti in altri linguaggi. Questo tipo di loop permette di iterare tra tutti i membri di un
oggetto (poiché i metodi sono membri con un particolare tipo, anche questi verranno elencati dal
loop) o gli elementi di un array (che, come vedremo, per Javascript sono molto simili agli oggetti).
La sintassi da usare un questo caso è
for (p in oggetto) {corpo}
La variabile di loop p viene aggiornata ad ogni iterazione con il nome o l'indice del successivo
elemento estratto da oggetto, quindi viene eseguito il corpo. E' da sottolineare, quindi, che p non
itera in effetti sui membri veri e propri, ma sulle loro chiavi di accesso. Per accedere al valore del
membro corrispondente, sarà sufficiente scrivere oggetto[p] (sintassi array), come vedremo in
dettaglio più avanti.
var o = new Object();
//itera tra le proprietà dell'oggetto o
for (p in o) {
o[p];
//preleva il valore della proprietà indicizzata dal loop (e dovrebbe
usarla...)
}
Funzioni
Le funzioni sono viste da Javascript come particolari tipi di oggetto. Per questo, oltre ad essere
chiamate, possono essere passate come argomento ad altre funzioni, copiate, assegnate ad
identificatori diversi e persino modificate a tempo di esecuzione.
Dichiarazione
In Javascript è possibile creare nuove funzioni con le seguenti sintassi:
•
•
•
Dichiarazione di funzione: sintassi function nome(parametri) {corpo}
Funzioni anonime: sintassi function(parametri) {corpo}
Oggetti funzione: sintassi new Function("parametri", "corpo")
Il nome di una funzione può essere qualsiasi nome valido per una variabile. I parametri della
funzione, se presenti, sono dichiarati tramite una lista di nomi (di variabile) separati da virgole. Le
parentesi dopo il nome della funzione vanno sempre inserite, anche se la lista dei parametri è
Revisione 05/11
Pagina 10/27
Corso di Ingegneria del Web
Javascript: Funzioni
vuota. Infine, il corpo della funzione è costituito da una sequenza di istruzioni Javascript valide
(ogni istruzione è separata dalla successiva da un punto e virgola.). Vediamo degli esempi:
//funzione senza parametri, dichiarazione diretta
function f(x,y) {...}
//funzione anonima assegnata a una variabile
var h1 = function(x,y) {...}
//oggetto funzione assegnato a una variabile
var h2 = new Function("x,y","...");
Nel primo caso, la dichiarazione è simile a quella di molti linguaggi di programmazione. Nel
secondo caso la funzione viene creata in maniera anonima (infatti la parola chiave function non è
seguita da alcun identificatore): per utilizzarla in qualche modo, quindi, è necessario passarla come
parametro a un'altra funzione o assegnarla ad una variabile, come nell'esempio qui sopra. Infine,
nel terzo caso, la lista dei parametri e il corpo sono passati sotto forma di stringa, quindi possono
essere anche generati in maniera dinamica. Anche in questo caso è necessario assegnare a una
variabile la funzione appena creata. Va notato che, una volta assegnata una funzione a una
variabile, questa variabile può essere usata a tutti gli effetti come la funzione assegnatagli, anche
se si tratta di una sua copia.
Nel corpo della funzione, come di consueto, è possibile utilizzare i parametri tramite il nome
delle variabili ad essi associate. Vediamo un altro esempio:
//funzione con due parametri, dichiarazione diretta
function g(a,b) {
var c = a + b;
return c;
}
Riferimento
Le funzioni Javascript sono in realtà variabili con valore di tipo Function (che, a sua volta, è un
particolare tipo di oggetto). Per fare riferimento a una funzione (ed esempio, per invocarla) è
quindi sufficiente usare il suo nome, o un'espressione equivalente che abbia valore di tipo
Function.
Una volta ottenuto il riferimento a una funzione è possibile chiamarla, specificando
eventualmente dei parametri, passarla come argomento ad un'altra funzione, assegnarla ad altre
variabili (che diventeranno altri riferimenti alla stessa funzione), accedere a tutte le proprietà del
corrispondente oggetto Function, per modificarla o ridefinirla, o infine verificare se è
effettivamente definita, come si farebbe con qualsiasi variabile. Vedremo queste operazioni dal
vivo man mano che ne faremo uso.
function app(f,x) {
return f(x);
}
//la funzione app applica il secondo parametro al primo
app(function(y){
return y+1;
},3);
//restituisce 4
Revisione 05/11
Pagina 11/27
Corso di Ingegneria del Web
Javascript: Funzioni
Chiamata
Per richiamare una funzione, si accoda la lista dei parametri, tra parentesi, a un'espressione che
ha fa riferimento alla funzione stessa. Questa espressione, nella maggior parte dei casi, è il nome
di una variabile o del membro di oggetto a cui è stata assegnata, esplicitamente o implicitamente,
una funzione.
Gli argomenti sono passati alla funzione come una lista di espressioni valide separate da virgole.
Si ricordi che, anche se la funzione non ha parametri, è comunque necessario specificare le due
parentesi dopo il nome. Vediamo qualche esempio
//definiamo qualche funzione
function f() {
var i;
};
var h1 = function(a) {
return a+1;
};
var h2 = new Function("a","return a+1;");
//esempi di chiamata
f(); //ritorna undefined, in quanto la funzione non ha alcun return
esplicito
var r = h1(3); //r=4
var r2 = h2(4); //r=5
(function(x){return x+1;})(3); //ritorna 4
L'ultimo esempio mostra come si può invocare come funzione qualsiasi espressione che
restituisca un valore di tipo Function: viene infatti definita una funzione anonima, alla quale viene
subito applicato l'operatore di invocazione, cioè le due parentesi con la lista dei parametri. La
funzione esisterà solo per il tempo della chiamata, non essendo associata ad alcun identificatore.
E' possibile omettere uno o più parametri al termine della lista degli argomenti. In questo caso,
tali parametri varranno undefined nel corpo della funzione, e sarà quindi possibile testarli ed
attribuite eventualmente valori di dafault a ciascuno di essi:
function f(x,y) {
//in questo modo, è come se y avesse un valore dei default
if (typeof(y)=='undefined') y=0;
return x+y;
}
f(3,1); //ritorna 4
f(3); //ritorna 3
f(); //ritorna undenfined o NaN (Not a Number), in quanto x non ha un
default e undefined+0=undefined
Passaggio di Parametri
Il passaggio dei parametri alle funzioni Javascript avviene in maniera diversa a seconda del tipo
del parametro stesso:
•
I tipi booleano, stringa, numero e null sono passati per valore. Nella funzione, cioè, è
presente una copia del valore usato come argomento. Cambiamenti locali alla funzione
non influenzano il valore dell'argomento usato nella chiamata alla funzione stessa.
Revisione 05/11
Pagina 12/27
Corso di Ingegneria del Web
•
Javascript: Closures
Il tipo oggetto è passato per riferimento. La manipolazione del contenuto dell'oggetto
all'interno della funzione si riflette sull'oggetto usato come argomento.
Ritorno
Le funzioni restituiscono il controllo al chiamante al termine del loro blocco di istruzioni. E'
possibile restituire un valore al chiamante, in modo da poter usare la funzione in espressioni più
complesse, utilizzando la consueta parola chiave return seguita da un'espressione valida. Se la
funzione non esegue alcuna return, Javascript sottintende un "return undefined" implicito.
Closures
Le funzioni Javascript, tra le loro tante peculiarità, hanno anche quella di generare delle closures,
una caratteristica molto utile nella pratica. Una closure (chiusura) è, tecnicamente, un'espressione
(tipicamente una funzione) associata a un contesto che valorizza le sue variabili libere.
Tutto il codice Javascript viene eseguito in un contesto, compreso quello globale. Tale contesto
viene utilizzato per dedurre il valore e lo stato di definizione di tutti gli identificatori. In particolare,
ogni esecuzione di una funzione ha un contesto associato, che contiene i valori delle variabili
globali e delle sue variabili locali.
Una closure si crea proprio a partire da una funzione, quando quest'ultima restituisce come
valore di ritorno una nuova funzione creata dinamicamente (cioè tramite gli ultimi due costrutti
di definizione visti in precedenza). La closure, cioè la funzione creata all'interno di un'altra funzione
e poi restituita, mantiene il contesto di esecuzione della funzione che l'ha creata. Questo significa
che il contesto di ciascuna chiamata della funzione "generatrice" non viene distrutto all'uscita
della funzione (cioè il valore delle sue variabili locali non viene dimenticato), come avviene in
generale, ma conservato in memoria.
La funzione closure potrà fare riferimento (in lettura e scrittura) ai parametri e alle variabili
dichiarate nel contesto della funzione che l'ha creata. Inoltre, poiché ogni chiamata a funzione ha
un suo contesto distinto, i valori "visti" dalla closure non saranno influenzati da successive
chiamate alla stessa funzione generatrice. Vediamo un esempio:
function generatrice(x) {
var y = 3;
return function(z) {
return x+y+z;
};
}
var f1
var f2
f1(0);
f2(0);
= generatrice(1);
= generatrice(2);
//restituisce 1+3+0 = 4
//restituisce 2+3+0 = 5
Nell'esempio, la funzione generatrice, ad ogni chiamata, restituisce una funzione che somma il
suo argomento al valore dell'argomento x e della variabile locale y della sua funzione generatrice.
Se chiamiamo due volte generatrice, le funzioni risultanti saranno distinte, in quanto ottenute
come closure da due invocazioni diverse della stessa funzione. L'esempio mostra infatti come le
funzioni f1 ed f2 si comportino in maniera diversa, sebbene siano entrambe generate dalla stessa
funzione generatrice.
Revisione 05/11
Pagina 13/27
Corso di Ingegneria del Web
Javascript: Closures
Un uso comune per le closure è fornire alcuni parametri a una funzione che verrà eseguita in
seguito: è il caso, ad esempio, delle funzioni passate come argomento a setTimeout (che verrà
illustrata più avanti). In pratica, quando passiamo una funzione come argomento, o la assegniamo
a una variabile, non possiamo fornirle parametri (inserire parametri verrebbe interpretato da
Javascript come una chiamata alla funzione): al posto della funzione possiamo però usare una
wrapper closure che la chiama con i parametri desiderati.
Vediamo un esempio chiarificatore. Definiamo una funzione f con un argomento, e poi vogliamo
assegnare alla variabile p la funzione f(3). Notare che non vogliamo assegnare a p il valore
ritornato dalla chiamata f(3), ma il codice della funzione f applicato al parametro 3, in maniera che
vanga ricalcolato ogni volta che invochiamo p. Infatti, poiché f usa al suo interno una variabile
globale v, il suo valore di ritorno non dipende solo dagli argomenti.
var v;
//globale
function f(x) {
return x+v;
//NOTA: il valore di ritorno dipende anche dalla variabile globale v
}
//vorremmo assegnare alla variabile p la FUNZIONE che restituisce f(3),
cioè 3+v
var p = f(3);
p(); //ERRATO: p non punta a una funzione, ma al valore calcolato come f(3)
al momento dell'assegnazione
p = f;
p(); //ERRATO: p è un riferimento a f, per cui necessita di un parametro
(avremmo dovuto scrivere p(3))
//la funzione che segue genera e restituisce una nuova funzione che chiama
f sul suo argomento y
function closureGenF(y) {
return function() {
return f(y);
}
}
p = closureGenF(3);
p(); //CORRETTO: verrà chiamata f(3)!
La soluzione è stata trovata con la generazione di una closure. Infatti, la funzione closureGenF
restituisce una funzione che chiama f sul parametro y passato a closureGenF stessa. La funzione
ritornata sarà una closure, e per questo sarà legata al particolare valore di y per cui è stata
generata. l'espressione closureGenF(3) crea quindi la funzione che volevamo assegnare a p.
Un altro esempio, che usa caratteristiche di Javascript che saranno più chiare di seguito, ma
mostra un'applicazione realistica delle closure, è il seguente.
//dobbiamo assegnare un handler per l'evento onclick a un elemento del DOM
HTML
htmlelement.onclick = f;
/*NOTA: anche qui non si possono passare parametri!
Accade spesso che si usino piccole varianti dello stesso so handler per
elementi diversi tali varianti sono semplici da costruire a tempo di
esecuzione (e spesso è necessario). Ad esempio, vogliamo associare a certi
elementi degli handler che colorino in rosso un elemento ad essi associato
Revisione 05/11
Pagina 14/27
Corso di Ingegneria del Web
Javascript: Oggetti Javascript
quando vengono cliccati.*/
function clickHandler(oToHighlight) {
return function(e) {
oToHighlight.style.backgroundColor="red";
}
}
element1.onclick = clickHandler(linkedelement1);
element2.onclick = clickHandler(linkedelement2);
In questo caso, ogni chiamata a clickHandler, a cui viene passato il riferimento a un certo
elemento, ritorna una funzione che, se chiamata, colora di rosso l'elemento dato.
Oggetti Javascript
Javascript non è un linguaggio object oriented, e il suo concetto di oggetto è molto più simile a
quello di un array associativo. In Javascript, infatti, non si possono definire classi, ma solo speciali
funzioni dette costruttori che creano oggetti aventi determinati membri. Il nome della funzione
costruttore è considerato il nome della classe dell'oggetto. Tra l'altro, gli oggetti Javascript
possono contenere metodi, ma questi ultimi sono considerati anch'essi valori, in quanto non sono
altro che oggetti di classe Function.
Non esiste vera ereditarietà negli oggetti Javascript, e non è possibile dichiarare delle gerarchie.
Tuttavia, Javascript contiene una classe base predefinita, chiamata Object.
Gli oggetti Javascript si creano utilizzando l'operatore new applicato alla loro funzione
costruttore. La funzione costruttore per l'oggetto base Object è predefinita in Javascript e può
essere utilizzata per creare un "oggetto vuoto":
var o = new Object();
Un metodo di creazione alternativo consiste nell'utilizzo del costrutto "parentesi graffe", che
crea un oggetto in maniera implicita e lo riempie con una serie di proprietà e metodi inizializzati.
La sintassi prevede una serie di coppie “nome” : valore, separate da virgole e inserite tra parentesi
graffe. I nomi devono essere identificatori validi, mentre i valori possono essere espressioni
qualsiasi. Ad esempio:
var o = { “p” : “a”, “x” : 2, “f” : function() {return 0;}}
L'esempio appena esposto crea un oggetto (assegnandolo poi alla variabile o) contenente una
proprietà p con valore "a" (stringa), una proprietà x con valore 2 (numero) e un metodo f il cui
codice è quello descritto nell'esempio sotto forma di funzione anonima.
Le Proprietà
Le proprietà di un oggetto Javascript possono contenere valori di qualsiasi tipo (comprese delle
funzioni!). Per accedere a una proprietà, si possono usare due sintassi:
•
•
Sintassi "a oggetti": oggetto.proprietà
Sintassi "array": oggetto["proprietà"]
Revisione 05/11
Pagina 15/27
Corso di Ingegneria del Web
Javascript: Oggetti Javascript
Ricordiamo che è disponibile anche lo speciale costrutto for...in per iterare tra le proprietà di un
oggetto, e che è possibile verificare se un oggetto ha una determinata proprietà con l'espressione
booleana proprietà in oggetto.
var o = {“pippo”: “ciao”, “pluto”: 3}; //creazione implicita di un oggetto
v = o["pluto"]; //equivalente a v = o2.pluto
//accediamo a una proprietà il cui nome è calcolato, e solo se questa
esiste
var nome = "pippo";
if (nome in o) v=o2[nome];
//iteriamo su tutte le prorietà di o
for(p in o) { ... } //p varrà, nell'ordine, pippo e poi pluto
Se si tenta di leggere il valore di una proprietà non definita in un oggetto, si ottiene il valore
undefined (come per ogni variabile non assegnata). Tuttavia, è possibile aggiungere
dinamicamente proprietà agli oggetti semplicemente assegnando loro un valore. In pratica,
Javascript crea automaticamente nuovi membri quando li si assegna, esattamente come crea
nuove variabili globali. Tuttavia, si ricordi che non è possibile aggiungere proprietà a variabili che
non siano di tipo oggetto.
var o = new Object();
var v = o.pippo; //v è undefined, in quanto o non ha questa proprietà
o.pluto = 3; //adesso o ha una proprietà "pluto", di tipo Number, con
valore 3
v = o.pluto; //adesso v è una variabile di tipo Number e vale 3
v.paperino = "ciao"; //è un errore: una variabile può accettare l'aggiunta
di proprietà solo se è di tipo oggetto!
La possibilità di aggiungere proprietà in maniera dinamica è spesso utilizzata anche per
uniformare l'interfaccia di oggetti di sistema, che i browser forniscono sotto forme differenti.
Infatti è possibile aggiungere nuove proprietà anche agli oggetti restituiti da particolari funzioni del
browser, magari deducendole da altre proprietà dell'oggetto stesso, in modo da dotarli di una
serie standard di membri. Vediamo un esempio avanzato, che chiariremo più avanti nelle lezioni
sul DOM HTML.
/*l'oggetto event, passato quando browser intercetta la pressione di un
tasto, contiene il codice del tasto premuto come valore di una proprietà il
cui nome varia a seconda del browser stesso. con lo statement che segue, ci
assicuriamo che esista sempre una proprietà keyCode con questo valore
nell'oggetto event */
event.keyCode= (event.keyCode)? event.keyCode: ((event.charCode)?
event.charCode: event.which);
I Metodi
I metodi di un oggetto Javascript sono semplicemente proprietà di tipo Function. Per accedere a
un metodo si possono usare le stesse sintassi viste per le proprietà. Per chiamare un metodo basta
accodare la lista dei parametri, tra parentesi, all'espressione di accesso al metodo. I metodi
possono essere aggiunti in qualsiasi momento a un oggetto, esattamente come le proprietà. Per
aggiungere un metodo a un oggetto, è sufficiente creare una proprietà col nome del metodo ed
Revisione 05/11
Pagina 16/27
Corso di Ingegneria del Web
Javascript: Oggetti Javascript
assegnarvi una funzione già definita, oppure una funzione anonima, come negli esempi che
seguono:
var o = {}; //metodo alternativo a new Object per creare un oggetto vuoto
o.f = function(x) {
return x+1;
}; //creazione metodo da funzione anonima
function zero(y) {return 0;}
o.g = zero; //creazione metodo a partire da funzione già definita
o["h"] = zero; //il metodo h è lo stesso assegnato a g
o.f; //restituisce un oggetto Function
o.f(3); //ritorna 4
o["g"](4); //ritorna 0
I metodi, per far riferimento alle proprietà e ad altri metodi dell'oggetto in cui sono definiti,
devono utilizzare la parola chiave this, come negli esempi che seguono. Va sottolineato che
omettendo this, Javascript cercherà le variabili col nome dato all'interno del metodo (variabili
locali) o tra le variabili globali, e non tra le proprietà dell'oggetto!
var o = {“pippo”: “ciao”, “pluto”: 3, “metodo3”: function(x) {return
pluto+x;}}
o.metodo3(1); //restituisce undefined o NaN, in quanto pluto non è una
variabile locale o globale a metodo3!
var o2 = {“pippo”: “ciao”, “pluto”: 3, “metodo3”: function(x) {return
this.pluto+x;}}
o.metodo3(1); //restituisce 4;
Funzioni Costruttore
Una funzione costruttore è un tipo speciale di funzione all'interno della quale si utilizza la parola
chiave this esclusivamente per assegnare proprietà di un (nuovo) oggetto. Una funzione
costruttore, inoltre, non deve ritornare alcun valore.
Le funzioni costruttore devono essere usate come argomento per l'operatore new, esattamente
come i nomi degli oggetti standard di Javascript, e non dovrebbero mai essere richiamate
direttamente (come normali funzioni). Quando si usa un costruttore con new, Javascript crea un
oggetto vuoto derivato da Object ed applica ad esso la funzione costrutture, al cui interno this
punta al nuovo oggetto: in questo modo, il costruttore può popolare l'oggetto, aggiungendo
proprietà e metodi. Vediamo un esempio.
//myObject è una funzione costruttore
function myObject(a) {
this.v = a+1;
this.w = 0;
this.m = function(x) {return this.v+x;}
}
/* L'oggetto o avrà due proprietà (v e w), una delle quali inizializzata
tramite il parametro della funzione costruttore, e un metodo (m) che
restituisce il valore della proprietà v sommata al suo argomento */
var o = new myObject(2);
o.m(3); //ritorna 6;
o.w = 7; //assegna un nuovo valore a una proprietà di o
Revisione 05/11
Pagina 17/27
Corso di Ingegneria del Web
Javascript: Oggetti Predefiniti Javascript
//si possono sempre aggiungere altri membri all'istanza dell'oggetto:
o.getW = function() {return this.w;}
Si ricordi sempre che i metodi inseriti in un oggetto, per fare riferimento alle proprietà
dell'oggetto stesso, devono riferirvisi attraverso this.
Oggetti Predefiniti Javascript
Le librerie standard di Javascript mettono a disposizione una serie di oggetti predefiniti, che
possono essere di enorme aiuto alla programmazione. Vediamone una rassegna.
String
Gli oggetti String sono usati in Javascript per contenere stringhe di caratteri. Possono essere
creati implicitamente, utilizzando una costante stringa, o esplicitamente tramite l'omonimo
costruttore:
s1 = "pluto";
s2 = new String("pippo");
I principali metodi e proprietà della classe String sono i seguenti. Tutti i metodi si applicano
all'oggetto di tipo String sul quale sono invocati.
•
•
•
•
•
•
•
•
•
length
restituisce la lunghezza della stringa.
charAt(posizione)
restituisce il carattere (stringa di lunghezza uno) alla posizione data (base zero).
charCodeAt(posizione)
come charAt, ma restituisce il codice ASCII del carattere.
indexOf(s[,offset])
restituisce la posizione della prima occorrenza (a partire da offset, se specificato) di della
sottostringa s nella stringa. Restituisce -1 se s non è presente.
lastIndexOf(s[,offset])
come indexOf, ma restituisce la posizione dell'ultima occorrenza.
substr(os[,l])
restituisce la sottostringa di lunghezza l (default, la massima possibile) che inizia os
caratteri dall'inizio della stringa
substring(os,oe)
restituisce la sottostringa che inizia os caratteri e termina a oe caratteri dall'inizio della
stringa
toLowerCase()
ritorna la stringa convertita in minuscolo
toUpperCase()
ritorna la stringa convertita in maiuscolo
RegExp
Javascript riconosce le espressioni regolari scritte nella sintassi Perl, che sono spesso molto utili
per eseguire parsing e validazione dei dati immessi dall'utente.
Revisione 05/11
Pagina 18/27
Javascript: Oggetti Predefiniti Javascript
Corso di Ingegneria del Web
Per informazioni approfondite sulla
http://perldoc.perl.org/perlre.html
sintassi
delle
espressioni
regolari
Perl-compatibili,
si
veda
Per descrivere un'espressione regolare costante è sufficiente usare la sintassi /espressione/
(notare l'assenza di virgolette: gli unici delimitatori sono gli slash). Espressioni regolari variabili
(cioè costruite a partire da espressioni stringa generate a tempo di esecuzione) possono essere
create tramite il costruttore RegExp.
E' possibile usare le espressioni regolari in vari metodi della classe String:
•
•
•
•
match(r)
restituisce un array con le sottostrighe che hanno fatto match con l'espressione regolare r.
replace(r,s)
restituisce una stringa in cui tutte le sottostringhe cha fanno match con r sono sostituite
con la stringa s.
search(r)
restituisce la posizione della prima sottostringa che fa match con r, o -1 se non ci sono
match.
split(r[,m])
divide la stringa in una serie di segmenti distinti dai separatori specificati con l'espressione r
e li restituisce come array. Se si indica un numero massima di occorrenze m, allora l'ultimo
elemento dell'array conterrà la rimanente parte della stringa.
var s = "ciao a tutti,mi chiamo paperino";
var tokens = s.split(/[ ,;!?]+/);
//restituisce l'array ['ciao','a','tutti','mi','chiamo','paperino']
s.replace(/[, ]/,"-").toUpperCase();
//restituisce "CIAO-A TUTTI,MI CHIAMO PAPERINO"
Per default, Javascript interrompe il processo di matching su una stringa appena trova un
riscontro per l'espressione regolare. Infatti, nell'ultimo esempio, solo il primo spazio viene
sostituito da un trattino. Per trovare tutti i riscontri possibili, usare il modificatore /g:
var s = "ciao a tutti,mi chiamo paperino";
s.replace(/[, ]/g,"-").toUpperCase();
//restituisce "CIAO-A-TUTTI-MI-CHIAMO-PAPERINO"
Si possono anche usare altri utili modificatori, ad esempio /i per rendere l'espressione regolare
case insensitive. Si veda la guida alle espressioni regolari Perl per ulteriori informazioni.
Array
Gli Array sono oggetti Javascript predefiniti, non hanno una dimensione fissa (come invece
avviene in molti linguaggi di programmazione) e possono contenere valori di qualsiasi tipo. Inoltre,
ogni elemento dell'array può avere tipo diverso (in altre parole gli array non sono omogenei).
Per creare un array si può usare
•
il costruttore Array, che accetta un numero arbitrario di parametri, corrispondenti agli
elementi con cui l'array deve essere inizializzato
Revisione 05/11
Pagina 19/27
Corso di Ingegneria del Web
•
Javascript: Oggetti Predefiniti Javascript
la sintassi simbolica "parentesi quadre", in cui gli elementi dell'array sono listati, separati
da virgole, tra sue parentesi quadre.
var a1 = new Array(10,20,30); //dichiarazione con costrutto new
var a2 = ["a","b","c"]; //dichiarazione implicita
Se si assegna un valore a un particolare indice di un array, si creano implicitamente tutti gli
elementi dell'array mancanti fino all'indice dato, inizializzandoli con undefined. In ogni momento è
possibile verificare se un indice è presente nell'array e il valore associato ad esso è diverso da
undefined con l'espressione booleana indice in variabile_array. Infine, per accedere a un elemento
di un array si usa la comune sintassi variabile_array[indice]. Gli elementi sono numerati a partire
da zero.
var a = new Array(10,20,30);
a[2]; //restituisce 30
(3 in a) //ha valore false
(4 in a) //ha valore false
a[4] = 0; //adesso l'array ha cinque elementi: [10,20,30,undefined,0]
(3 in a) //ha ancora valore false
(4 in a) //ha valore true
if (4 in a) { a[4] = a[4]+1; } //usa un elemento solo se presente
I principali metodi e proprietà della classe Array sono i seguenti:
•
•
•
•
•
•
length
restituisce la dimensione dell'array
concat(e1,e2,e3,...)
restituisce il nuovo array ottenuto concatenando gli elementi dati alla fine dell'array.
join([separatore])
converte l'array in una stringa, concatenando la versione String di ciascun elemento tramite
il separatore dato (default ",").
reverse()
restituisce una copia dell'array con gli elementi in ordine inverso
slice(os[,l])
restituisce il sotto array di lunghezza l (default, fino alla fine dell'array sorgente) che inizia
all'indice os.
sort([sortfun])
restituisce l'array ordinato. La funzione opzionale sortfun può essere usata per specificare
un criterio di ordinamento non standard. Tale funzione deve accettare due parametri e
restituire 0 (elementi uguali), -1 (il primo è minore del secondo) o 1 (il primo è maggiore del
secondo).
for (i in a) {
a[i];
} //itera nell'array a
for (i=0; i<a.length; ++i) {
a[i];
} //itera tra gli elementi dell'array
Revisione 05/11
Pagina 20/27
Corso di Ingegneria del Web
Javascript: Oggetti Predefiniti Javascript
[3,1,2].sort( function(x,y){return x<y;});
//ordina l'array in maniera decrescente
Molti linguaggi (ad esempio PHP) dispongono del concetto di array associativo, in cui gli elementi
sono associati a chiavi generiche di tipo stringa, e non a semplici indici numerici. Questo costrutto
nella pratica è molto utile, e si può facilmente ottenere anche in Javascript. Infatti, per avere un
array associativo, è sufficiente creare dinamicamente delle proprietà (chiavi) a partire da un
oggetto vuoto. La possibilità di accedere alle proprietà con la sintassi tipica degli array, cioè o["p"],
rende in questo senso gli oggetti Javascript identici a un array associativo.
//è un oggetto Javascript, ma lo usiamo come un array associativo!
aa = {};
aa["nome"] = "Pippo";
aa["eta"] = 34;
Date
L'oggetto Date permette di manipolare valori di tipo data e ora. Dispone di diversi costruttori:
•
•
•
Date()
inizializza l'oggetto alla data/ora corrente.
Date(y,m,d,hh,mm,ss)
inizializza l'oggetto alla data/ora d/m/y hh:mm:ss.
Date(stringa)
tenta di riconoscere la stringa come una data e inizializza l'oggetto di conseguenza.
Gli oggetti Date possono essere confrontati tra loro con i normali operatori di confronto, inoltre i
metodi degli oggetti Date permettono di leggerne e scriverne le componenti separatamente: ad
esempio, possiamo usare i metodi getYear, getMonth, setYear, setMonth, getDay (restituisce il
giorno della settimana), getDate (restituisce il giorno del mese), setDate (imposta il giorno del
mese)
Una caratteristica utile del metodo setDate è che, se il valore passato è maggiore del massimo
consentito, la funzione gestisce automaticamente l'incremento del mese/anno della data. Se
vogliamo quindi aggiungere dieci giorni a una data d, dovremo semplicemente scrivere
d.setDate(d.getDate()+10). Se il valore passato a setDate è negativo, la data viene invece spostata
nel passato. Vediamo altri esempi:
//genera un saluto adeguato all'ora corrente e lo assegna alla variabile
saluto
var giorni = ["lun","mar","mer","gio","ven","sab"];
var mesi =
["gen","feb","mar","apr","mag","giu","lug","ago","set","ott","nov","dic"];
var oggi = new Date();
var data = giorni[oggi.getDay()] + " " + oggi.getDate() + " " +
mesi[oggi.getMonth()] + " " +oggi.getFullYear();
var saluto;
if (oggi.getHours() > 12) saluto = "Buona sera, oggi è il "+data;
else saluto = "Buongiorno, oggi è il "+data;
//calcola una la data di 70 giorni nel futuro futuro = new Date();
futuro.setDate(oggi.getDate()+70);
Revisione 05/11
Pagina 21/27
Corso di Ingegneria del Web
Javascript: Oggetti Predefiniti Javascript per i Browser
Oggetti Predefiniti Javascript per i Browser
Quando Javascript è eseguito all'interno di un browser, altri oggetti predefiniti, relativi al browser
stesso e alla pagina visualizzata, sono disponibili per l'uso. Vediamo i più interessanti e utili.
window
L'oggetto window è il punto di accesso a tutti gli oggetti esposti dal browser. Si tratta
dell'oggetto predefinito per lo scripting, il che significa che tutte le sue proprietà e i suoi metodi
sono accessibili a livello globale, senza bisogno di specificare esplicitamente il nome dell'oggetto
window.
L'interfaccia di window contiene alcune funzionalità molto utili, tra cui
•
•
•
•
alert(messaggio)
mostra il messaggio dato in un dialog box (con il solo bottone OK).
confirm(messaggio)
mostra il messaggio dato in un dialog box con I bottoni OK e Cancel. La funzione ritorna
true se l'utente preme OK, false altrimenti.
prompt(messaggio,default)
mostra il messaggio dato in un dialog box, insieme a un campo di input con valore iniziale
default. Se l'utente preme OK, il contenuto del campo (anche vuoto) viene restituito dalla
funzione, altrimenti la funzione restituisce null.
setTimeout e setInterval
permettono di impostare i timer (si veda dopo)
//esegue un'azione solo se l'utente clicca OK
if (window.confirm("Sei sicuro di voler lasciare questa pagina?")) {...}
//chiede all'utente di inserire un dato e lo avverte se non è stato
specificato nulla
var citta = window.prompt("Luogo di Nascita","L'Aquila");
if (!citta) window.alert("Non hai specificato il luogo di nascita!");
La proprietà document permette di accedere al (modello a oggetti del) documento HTML
visualizzato, di cui parleremo di seguito. Altre proprietà, come ad esempio statusbar, sono
supportate in maniera diversa dai differenti browser.
document
L'oggetto document, accessibile tramite la proprietà omonima di window, rappresenta il
documento visibile nel browser. La maggior parte dei metodi e delle proprietà offerti dall'oggetto
document provengono dall'interfaccia Document, che verrà trattata nell'ambito del Document
Object Model. Esistono tuttavia alcune proprietà utili proprie del solo oggetto document, ad
esempio:
•
•
La proprietà location
contiene la URL di provenienza del documento corrente.
La proprietà lastModified
contiene la data dell'ultimo aggiornamento del documento corrente.
Revisione 05/11
Pagina 22/27
Corso di Ingegneria del Web
•
•
•
Javascript: L'oggetto XMLHttpRequest
Il metodo open()
apre uno stream per la successiva scrittura di testo nel documento tramite write() e
writeln(). All'apertura dello stream il contenuto corrente del documento viene cancellato.
I metodi write(testo) e writeln(testo)
accodano testo (o testo seguito da un ritorno a capo) al documento corrente. Se non è stata
chiamata la open(), ne viene generata una implicita.
Il metodo close()
chiude lo stream di scrittura aperto con open() e forza la visualizzazione di quanto scritto
nel documento con write() e writeln(). Ogni successiva operazione di scrittura genererà una
nuova open() implicita.
Attenzione: I metodi open, close, write e writeln non si possono usare in XHTML.
L'oggetto document fornisce anche un sistema "proprietario" di Javascript per l'accesso alla
struttura del documento visualizzato. Nei browser moderni, con supporto al W3C DOM, l'uso di
questo sistema è tuttavia fortemente sconsigliato.
//crea un documento contenente una semplice tabella - non funziona in
modalità standards
var i,j;
document.open();
document.write("<table border=‘1'>");
for(i=0;i<10;++i) {
document.write("<tr>");
for(j=0;j<10;++j) {
document.write("<td>"+i+","+j+"</td>");
} document.write("</tr>");
} document.write("</table>");
document.close();
L'oggetto XMLHttpRequest
L'oggetto XMLHttpRequest, originariamente introdotto da Internet Explorer, è ora supportato da
tutti i browser più diffusi. Il suo scopo è quello di permettere al codice Javascript l'esecuzione di
richieste HTTP verso il server (proprio come farebbe il browser) e la gestione dei dati risultanti.
Questo oggetto è alla base delle tecniche AJAX, con cui gli script che controllano una pagina web
possono dialogare col server senza la necessità di "cambiare pagina".
Attenzione: per motivi di sicurezza, l'oggetto XMLHttpRequest può effettuare connessioni solo
con l'host a cui appartiene la pagina in cui ha sede lo script!
L'interfaccia di XMLHttpRequest è standard, ma esistono sistemi browser-dipendenti per
accedere a questo oggetto. Se nel browser è definito il costruttore omonimo (lo si può verificare
con l'espressione typeof(XMLHttpRequest) != "undefined"), è sufficiente eseguire una new. In
Internet Explorer, si usa invece il costruttore ActiveXObject passandogli la stringa di
identificazione dell'oggetto, che può essere "MSXML2.XmlHttp.6.0" (preferita) o
"MSXML2.XmlHttp.3.0" (vecchie versioni del browser). Riassumendo, un modo crossbrowser per
ottenere un riferimento a XMLHTTPRequest è dato dal frammento di codice che segue;
function createRequest() {
var ACTIVEXIDs=["MSXML2.XmlHttp.6.0","MSXML2.XmlHttp.3.0"];
if (typeof XMLHttpRequest != "undefined") {
return new XMLHttpRequest();
Revisione 05/11
Pagina 23/27
Corso di Ingegneria del Web
Javascript: L'oggetto XMLHttpRequest
} else if (typeof ActiveXObject != "undefined") {
for (var i=0; i < ACTIVEXIDs.length; i++) {
try {
return new ActiveXObject(ACTIVEXIDs[i]);
} catch (oError) {
//l'oggetto richiesto non esiste: proviamo il successivo
}
}
alert("Impossibile creare una XMLHttpRequest");
} else {
alert("Impossibile creare una XMLHttpRequest");
}
}
Il pattern d'uso di XMLHttpRequest è duplice, a seconda che si scelga la modalità di chiamata
sincrona o asincrona:
•
•
Modalità sincrona: la richiesta al server blocca lo script (e la pagina associata) finché non
viene ricevuta la risposta.
Modalità asincrona: la richiesta viene inviata, e lo script continua la sua esecuzione,
venendo poi avvisato dell'arrivo della risposta tramite un evento.
Uso Sincrono
Per usare XMLHttpRequest in maniera sincrona, si prepara la richiesta usando il metodo open, a
cui si passano il verbo HTTP e la URL da chiamare. Il terzo parametro deve essere false per avviare
una richiesta sincrona. Si invia quindi la richiesta con il metodo send, che risulta bloccante.
xhr.open("GET","http://pippo",false);
xhr.send(null);
Si controlla infine se la richiesta ha restituito un errore HTTP tramite la proprietà status e, in caso
di successo, si accede ai dati restituiti dal server tramite la proprietà responseText
if (xhr.status !=404) {
//404 è il codice di errore "not found" di HTTP
alert(xhr.responseText);
} else {
alert("errore");
}
Uso Asincrono
In questo caso, si prepara la richiesta usando il metodo open, a cui si passano come al solito il
verbo HTTP e la URL da chiamare. Il terzo parametro in questo caso deve essere true per avviare
una richiesta asincrona. Si imposta quindi l'handler da chiamare quando la richiesta sarà stata
servita assegnando una funzione alla proprietà onreadystatechange. Infine si invia la richiesta con
il metodo send (la chiamata ritorna immediatamente il controllo allo script).
xhr.open("GET"," http://pippo",true);
xhr.onreadystatechange = handler;
xhr.send(null);
All'interno dell'event handler dichiarato con onreadystatechange, che sarà chiamato ad ogni
cambio di stato della richiesta, si verifica prima di tutto se la richiesta è stata effettivamente
Revisione 05/11
Pagina 24/27
Corso di Ingegneria del Web
Javascript: Gestione delle Eccezioni
servita controllando che la proprietà readyState sia uguale a 4. In tal caso, si può verificare se
l'esecuzione ha restituito un errore HTTP tramite la proprietà status e poi accedere ai dati restituiti
dal server tramite la proprietà responseText, come già illustrato per il caso sincrono.
function handler() {
if (xhr.readyState==4) {
if (xhr.status!=404) {
alert(xhr.responseText);
} else {
alert("errore");
}
}
}
In ogni momento, è possibile invocare il metodo abort per interrompere la richiesta HTTP in
corso. E' ovviamente possibile attivare più chiamate asincrone contemporaneamente. In questo
caso, ogni handler dovrà fare riferimento ad un'istanza diversa di XMLHttpRequest.
Ajax e JSON
Spesso, quando si scambiano dati con uno script tramite la XMLHttpRequest, accade che il server
debba passare a Javascript strutture dati complesse, e non semplice testo o HTML. In questi casi,
è utile usare la notazione JSON: in pratica, le strutture dati vengono trascritte testualmente
usando la notazione "breve" Javascript per la definizione di oggetti ed array.
Ad esempio, la stringa che segue definisce (e in Javascript crea) un array contenente due record
aventi come campi "id" e "nome"
[{id:1, nome:'pippo'},{id:2, nome:'pluto'}]
Il server dovrà quindi codificare tutti i dati da inviare allo script in questo formato. Una volta
ricevuti i dati, lo script potrà trasformarli facilmente in vere strutture dati sfruttando la capacità
di Javascript di interpretare stringhe come fossero codice. In particolare, il metodo più sicuro per
effettuare questa trasformazione è il seguente:
dati = new Function("return "+xhr.responseText)();
In pratica, si crea una funzione anonima che ritorna le strutture generate dall'interpretazione dei
dati in formato JSON, e la si chiama contestualmente (si noti infatti la coppia di parentesi dopo la
chiusura del costruttore Function).
Gestione delle Eccezioni
Nelle versioni più recenti di Javascript è stato introdotto anche un sistema di gestione delle
eccezioni in stile Java. Un’eccezione segnala un imprevisto, spesso un errore, all’interno della
normale esecuzione del codice.
Non ci proponiamo di dare qui una definizione completa del concetto di eccezione e del modo in cui può essere
utilizzata per migliorare la struttura del codice, in particolare la gestione degli errori. Per approfondire questi
argomenti, potete riferirvi allo stesso argomento presente su qualsiasi libro di programmazione object oriented.
Un’eccezione può venire sollevata dalle librerie di Javascript o dal codice scritto dall’utente,
attraverso la parola chiave throw. Una volta sollevata, un’eccezione risale lo stack di Javascript
finché non viene gestita da un handler esplicito (dichiarato dall’utente) o implicito (inserito nel
Revisione 05/11
Pagina 25/27
Corso di Ingegneria del Web
Javascript: Funzioni Javascript Utili: i Timer
runtime Javascript). Ciò significa che un’eccezione generata in una funzione, se non viene gestita
all’interno di quest’ultima, si propagherà alle sue funzioni chiamanti, fino ad arrivare al runtime di
Javascript, che la presenterà all’utente come un messaggio di errore (nelle modalità specificate dal
browser).
Per gestire le eccezioni generate (eventualmente) da un particolare blocco di codice, è possibile
avvalersi del costrutto try…catch, che permette di dichiarare un handler associato a uno specifico
blocco di codice. Qualsiasi eccezione sollevata all’interno del codice compreso tra try e catch verrà
passata al codice di gestione dichiarato dopo catch. Le eccezioni generate da Javascipt e catturate
dai blocchi catch sono oggetti la cui proprietà message riporta il messaggio di errore associato.
try {
…codice…
} catch(e) {
alert(“Eccezione sollevata: ”+ e.message);
}
Le eccezioni generate dall’utente tramite la parola chiave throw possono essere invece oggetti
qualsiasi, che verranno presentati come tali al blocco catch.
try {
…codice…
throw {“nome”: “pippo”, “valore”: 1};
} catch (ex) {
alert(“Valore dell’eccezione: ”+ ex.valore);
}
Se ci si vuole assicurare che un certo codice sia eseguito sempre dopo il blocco protetto da
try…catch, indipendentemente dal sollevamento di eccezioni, è possibile aggiungere al blocco la
clausola finally. In tal caso, il codice finally verrà eseguito in ogni caso prima che l’interprete
Javascript passi ad eseguire del codice diverso da quello inserito nel costrutto try…catch.
try {
…codice…
} catch (eccezione) {
…gestione dell’eccezione…
} finally {
…codice eseguito in ogni caso prima che l’esecuzione prosegua oltre il
blocco try…catch…
}
Funzioni Javascript Utili: i Timer
Javascript, tramite l'oggetto window, permette anche di eseguire azioni temporizzate. A questo
scopo si usano i seguenti metodi.
•
•
setTimeout(stringa_o_funzione,millisecondi,arg1,...,argN).
La chiamata a questa funzione fa sì che, dopo il numero specificato di millisecondi,
Javascript esegua il codice dato dal primo argomento, che può essere una stringa
contenente del codice da valutare o il nome di una funzione da chiamare. In quest'ultimo
caso, è possibile specificare opzionalmente una serie di argomenti (arg1...argN) da passare
alla funzione. L'azione viene quindi eseguita una sola volta.
setInterval(stringa_o_funzione,millisecondi,arg1,...,argN).
La chiamata a questa funzione fa sì che, ogni millisecondi, Javascript esegua il codice dato
Revisione 05/11
Pagina 26/27
Javascript: Funzioni Javascript Utili: i Timer
Corso di Ingegneria del Web
dal primo argomento, che può essere una stringa contenente del codice da valutare o il
nome di una funzione da chiamare. In quest'ultimo caso, è possibile specificare
opzionalmente una serie di argomenti (arg1...argN) da passare alla funzione. L'azione
viene quindi eseguita periodicamente.
Entrambe le funzioni possono essere chiamate più volte, e restituiscono un timer id (numerico),
tramite il quale è possibile annullare le azioni usando le rispettive funzioni:
•
•
clearTimeout(id) per le azioni avviate con setTimeout()
clearInterval(id) per le azioni avviate con setInterval()
Vediamo alcuni esempi d'uso per queste due funzioni:
function saluta(nome) {
alert("Ciao "+nome);
}
//Richiede il nome e saluta dopo cinque secondi
var nome = prompt("Come ti chiami?");
if (nome) setTimeout(saluta,5000,nome);
//avverte dell'ora corrente ogni minuto
setInterval("d=new Date(); alert('Ora sono le
'+d.getHours()+':'+d.getMinutes())",60000);
This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported
License. To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a
letter to Creative Commons, 444 Castro Street, Suite 900, Mountain View, California, 94041, USA.
Revisione 05/11
Pagina 27/27

Documenti analoghi

Javascript - University of L`Aquila

Javascript - University of L`Aquila Passare come argomento una funzione ad un’altra funzione. Assegnare una funzione a una o più variabili. Accedere a tutti gli elementi della funzione, per modificarla o ridefinirla, tramite le propr...

Dettagli