Corso JavaScript (parte 2)
A cura di Gabriele Favrin
Articolo pubblicato su Amiga Life 109 (marzo 2000)
Nota bene: l'articolo proposto in questa pagina è
proprietà dell'autore e non può essere distribuito o
riutilizzato in alcun modo o forma senza il suo consenso scritto.
Le informazioni qui riportate risalgono alla data di pubblicazione
dell'articolo e non è detto che siano ancora valide o
che rispecchino lo stato attuale dei programmi, le posizioni delle persone
interpellate o quelle degli autori stessi.
Avviso
Questo corso descrive JavaScript 1.1. Sebbene le informazioni proposte siano valide come punto di partenza per la conoscenza del linguaggio, suggerisco agli interessati di seguire guide aggiornate alla versione più recente di JavaScript che offre funzionalità avanzate come la gestione di dati XML esterni e la completa manipolazione dell'aspetto del documento.
Introduzione
Nella scorsa puntata abbiamo visto come inserire script all'interno di
documenti HTML e presentato le principali caratteristiche del
linguaggio, anche con l'ausilio dei numerosi esempi su CD,
evidenziandone similitudini con il C. Già ora quindi il
lettore è in grado di sviluppare semplici script che, ad
esempio, visualizzano un testo generato dinamicamente.
Il codice proposto sinora presenta una caratteristica comune: viene
eseguito man mano che il browser carica il documento. Questa soluzione
può creare problemi qualora, per esempio, il caricamento
venga interrotto da un errore o per volontà dell'utente. In
questo caso il browser si troverebbe con uno script incompleto e
probabilmente dai risultati imprevedibili se non addirittura deleteri.
Il nostro codice, inoltre, non è utilizzabile da altri
script o dai gestori di evento (di cui parleremo in seguito). Per
risolvere questo problema è possibile, e consigliabile, fare
ricorso alle funzioni.
Le funzioni
Le funzioni sono segmenti di codice identificati da un nome e che vengono definiti in un primo tempo ed eseguiti solo in seguito. Vediamo un esempio, ricordando che i numeri di linea sono presenti solo come riferimento e non vanno trascritti!
2 <html><script type="text/javascript" language="JavaScript"> 4 function ciao() 6 { 8 alert('ciao'); 10 return true; 12 } 14 </script></html>
Chi ha letto con attenzione il paragrafo precedente, avrà
già intuito che questo documento non genera alcun output. La
funzione è definita nelle linee da 4 a 12 ma poi non
è "invocata". Prima di porre rimedio a questa mancanza,
analizziamo lo script.
La linea 4 contiene l'istruzione "function" che indica che
ciò che segue è una funzione e non del codice da
eseguire immediatamente. Da questo punto e fino alla fine della
funzione (cioè alla linea 12, con la chiusura della coppia
di parentesi graffe che racchiude il codice), l'interprete si
limiterà a immagazzinare le istruzioni. Seguono a "function"
il nome della funzione stessa e due parentesi tonde nelle quali si
possono indicare i nomi di una o più variabili che saranno
usati per riferirsi agli eventuali argomenti passati alla funzione.
Proviamo ora a modificare alcune linee dello script:
4 function ciao(testo) 8 alert(testo);
In questo modo la funzione è stata "parametrizzata" e può essere utilizzata per visualizzare testo variabile e non soltanto la stringa "ciao". Proviamo, inserendo, dopo la linea 12:
13 ciao('ciao a tutti');
Ricaricando il documento vedremo un requester contenente il testo "ciao
a tutti", come effetto dell'esecuzione della relativa funzione. Va
detto che gli argomenti in JavaScript non sono fissi: volendo
è possibile inserirne più di quelli accessibili
tramite le variabili specificate nella funzione. In questo
caso vi potrà accedere tramite l'array "arguments".
Notare il "return true" alla fine della funzione. Ogni funzione DEVE
terminare con l'istruzione "return" (letteralmente indica il ritorno al
codice che ha invocato la funzione stessa). Dopo l'istruzione
è possibile specificare un valore o un'espressione che
sarà restituita come risultato della funzione. La si
può anche omettere, con il rischio però di
incorrere in qualche oscuro errore di esecuzione di NS. Ovviamente per
servirci di quel valore dovremmo invocare la funzione all'interno di
un'assegnazione (es. "var a=ciao();
", esegue la funzione ed
assegna ad a il risultato) o di un'espressione
(es. "if (ciao()==true)"
).
I gestori di evento
Finora abbiamo descritto script la cui esecuzione è
automatica e coincide col caricamento del documento. In
realtà può essere necessario eseguire operazioni
in base alle azioni dell'utente. Potremmo voler ad esempio visualizzare
un messaggio quando l'utente sposta il puntatore del mouse sopra un
link, quando cerca di inviare un modulo o se interrompe il caricamento
del documento. JavaScript ci mette a disposizione numerosi gestori di
evento ("event handlers") destinati proprio a questo scopo.
Contrariamente a quanto ci si potrebbe aspettare, i gestori di evento
vanno collocati all'interno degli elementi HTML e non in uno script. Ad
essi può essere associata l'esecuzione di un'espressione
JavaScript (nella più vasta accezione del termine). Prestare
attenzione al fatto che il risultato dell'espressione (sia essa
composta di singole istruzioni o dal richiamo a una funzione)
può variare il successivo comportamento del browser. Un
esempio:
<a href="http://www.cnn.com" OnMouseOver="alert('Le ultime notizie dal mondo')" OnClick="alert('State per lasciare questo sito')">CNN</a>
In questo caso l'evento "OnMouseOver" (letteralmente "al passaggio del mouse") causa la visualizzazione di un requester contenente del testo, mentre "OnClick" esegue la stessa operazione quando l'utente "clicca" sul link per accedere al sito. Se però avessimo fatto seguire ad "alert()" l'istruzione "return false" il browser non avrebbe aperto la nuova pagina. Con una piccola modifica il concetto sarà più chiaro:
<a href="http://www.cnn.com" OnClick="return confirm('Siete sicuri di voler leggere le ultime notizie?')">CNN </a>
Questa volta "return" restituisce al browser il risultato
dell'espressione che lo segue, precisamente "confirm" che presenta un
requester con le opzioni "OK" e "Cancel" e restituisce true o false a
seconda della scelta fatta dall'utente. Ricevendo false, il browser non
aprirà il link.
E' opportuno soffermarsi ad osservare attentamente l'uso delle
virgolette in questi primi esempi. Poichè i gestori di
evento sono visti come attributi degli elementi HTML, essi devono
rispettare sia le regole HTML sia quelle JavaScript. Come attributi
HTML devono essere inseriti fra virgolette (possibilmente doppie, dato
che non tutti i browser riconoscono quelle singole). Qualora risulti
necessario servirsi di virgolette all'interno di un comando JavaScript,
bisognerà ricorrere alle singole. Per usare virgolette
singole all'interno di una stringa si potrà poi ricorrere al
carattere di escape "\" (operazione che sarebbe comunque meglio evitare
per non incorrere in problemi con i browser non compatibili
JavaScript). Lo schema da seguire è fondamentalmente questo:
<elemento_HTML evento_JS="funzione_o_comando_JS('questo e\' un esempio')">
Sbagliare o anche solo invertire l'ordine delle virgolette od ometterne
una può portare alla mancata visualizzazione di parti del
documento.
Esistono numerosi gestori di evento, onMouseOver ed onClick (che al
momento né V3 né IB2.1 sembrano supportare
correttamente) sono solo i più comuni. E'
possibile intercettare la modifica o l'attivazione e disattivazione dei
componenti di un modulo, nonché la pressione del relativo
bottone di invio. Naturalmente ogni elemento HTML ha i propri eventi
specifici. A questo proposito va precisato che, sebbene l'HTML4 abbia
introdotto gestori di evento per quasi ogni elemento, allo stato
attuale, su Amiga almeno, JavaScript può essere utilizzato
solo con gli elementi specificatamente previsti dal linguaggio. Per una
panoramica degli elementi e relativi eventi disponibili vi rimandiamo
alle specifiche ufficiali JavaScript presenti sul CD.
Negli esempi proposti abbiamo utilizzato prevalentemente requester per
comunicare informazioni all'utente. Una soluzione rapida ma invasiva: a
chi piacerebbe vedere un requester aprirsi solo perché ha
spostato il mouse su un link? Uno degli utilizzi più
frequenti di JavaScript consiste, invece, nell'associare ai link
descrizioni esplicative inserite nella barra dell'URL.
<a href="http://www.cnn.com" onMouseOver="window.status='Le ultime notizie dal mondo'" onMouseOut="window.status=''">CNN</a>
Sui gestori d'evento non dovrebbe esserci molto da dire. Notare solo l'uso di onMouseOut per "pulire" la linea di stato dopo che il mouse è stato spostato dal link. Ma cos'è "window.status"? Lo capiremo addentrandoci nel cuore di JavaScript.
Gli oggetti
JavaScript è un linguaggio ad oggetti. La programmazione ad oggetti propone una filosofia di lavoro diversa dalle tecniche classiche. Per taluni è il miglior sistema di sviluppo e certamente favorisce una più chiara organizzazione del programma e dei dati. Non è questa la sede per una disquisizione ad alto livello su oggetti e relativa filosofia d'uso. Pertanto cercheremo di rendere la cosa comprensibile quel tanto che basta a consentire, a chi fosse digiuno di queste tecniche di programmazione, la padronanza di JavaScript. Ci perdonino i più esperti.
Per descrivere gli oggetti faremo un parallelo con il mondo reale
prendendo come esempio un boing, la palla a scacchi bianchi e rossi di
cui la scena Amiga da qualche tempo pullula. Un boing è un
oggetto con delle caratteristiche e delle funzioni. Fra le
caratteristiche possiamo citare la dimensione, la forma, il materiale
di cui è composto, il numero di scacchi totale, ecc. Fra le
sue funzioni, quelle di rimbalzare e rotolare, per esempio.
Un boing, insomma, è un oggetto nella realtà.
Allo stesso modo, in un linguaggio ad oggetti possiamo definire un
oggetto e deciderne le caratteristiche (dette "proprietà") e
le funzioni ("metodi"). Le proprietà possono essere lette e
talvolta modificate mentre i metodi possono essere invocati con le
stesse modalità delle funzioni JavaScript, che per inciso
altro non sono se non "metodi" del documento in cui sono definite. Per
riferirsi agli oggetti si utilizza la forma "oggetto.metodo()" oppure
"oggetto.proprietà". Qualche esempio pratico:
boing.volume
Proprietà che contiene il volume dell'oggetto boing.
Può essere letta con "var a=boing.volume;
"
e modificata (quando possibile) con "boing.volume=valore;"
boing.rotola()
o boing.rimbalza()
Metodi che invocano le relative funzioni dell'oggetto boing.
Nella realtà per riferirci ad un oggetto utilizziamo il suo
nome (non diremo, infatti, "passami l'oggetto" ma "passami il boing") e
così possiamo fare anche in JavaScript. Ad un oggetto
è possibile assegnare un altro nome, ad esempio con
"var palla=boing
" assegnamo a "palla" il nostro boing e potremo utilizzare
indifferentemente entrambi i nomi per riferirci allo stesso oggetto.
Possiamo anche creare dei nuovi oggetti, separati dai precedenti ma con
le stesse caratteristiche: "var palla2=new boing
" crea una nuova
istanza del boing totalmente indipendente dalla prima, proprio come se
costruissimo una palla nuova basata sul modello denominato "boing".
Il parallelo realtà/programmazione termina qui in quanto nella realtà non è possibile concatenare oggetti e proprietà come lo è in programmazione. Parlando di concatenazione ci riferiamo al fatto che ogni oggetto può essere una proprietà di altri oggetti o possederne di propri. Ad esempio il colore di sfondo di un documento ("bgcolor") è una delle proprietà dell'oggetto "document", a sua volta proprietà dell'oggetto "window" (finestra). JavaScript è infatti interamente costituito da oggetti. Stringhe, numeri e array sono tutti oggetti. I documenti HTML sono rappresentati da una lunga serie di oggetti spesso contenuti all'interno di array.
Qualche esempio: fra le proprietà dell'oggetto array
troviamo "length" che indica il numero degli elementi contenuti
nell'array. Tutte le immagini presenti in un documento sono visibili da
JavaScript all'interno dell'array "images", proprietà
dell'oggetto "document". Il comando "alert(document.images.length);"
visualizza quindi il numero di immagini presenti nella pagina. Gli
elementi dell'array immagini sono oggetti di tipo "image", con numerose
proprietà fra le quali spicca "src" che indica il sorgente
dell'immagine ed è modificabile.
Iniziamo a mettere in pratica quanto appreso. Sappiamo che tramite i
gestori di evento è possibile intercettare il passaggio del
mouse su un link e che si può modificare il sorgente di
un'immagine in maniera dinamica (cioè anche dopo che il
documento che la contiene è stato caricato). La prima cosa
che viene in mente è di cambiare le immagini della nostra
pagina al passaggio del mouse, per evidenziarle e attrarre l'attenzione
del visitatore. Vediamo come, tenendo presente che i due esempi che
seguono non funzionano correttamente su IB2.1 per limiti della sua
attuale implementazione JavaScript.
<a href="http://www.pluricom.it/amigalife/index.html" onMouseOver="document.images[0].src='logo_eal_color.gif'" onMouseOut="document.images[0].src='logo_eal_bw.gif'"> <img src="logo_eal_bw.gif"></a>
Il sistema usato per riferirsi all'immagine non è fra i più immediati poichè passa attraverso l'array delle immagini e quindi costringe ad indicarne il numero (che varia a seconda della posizione dell'immagine nel documento). E' preferibile quindi assegnare un nome all'oggetto tramite l'attributo "name" dell'elemento HTML "img":
<a href="http://www.pluricom.it/amigalife/index.html" onMouseOver="document.logo.src='logo_eal_color.gif'" onMouseOut="document.logo.src='logo_eal_bw.gif'"> <img name="logo" src="logo_eal_bw.gif"></a>
Assegnando diversi nomi alle immagini possiamo tranquillamente ottenere
ogni sorta di effetto: non solo loghi che cambiano colore, come in
questo caso, ma anche l'effetto pressione di un pulsante o la modifica
di un'altra immagine che aiuti a comprendere il contenuto del link.
Tutto sta a specificare il nome dell'immagine da modificare ed il nuovo
URL. In pagine complesse potremmo voler creare una funzione
parametrizzata da far invocare ai gestori di evento per non dover
scrivere ogni volta l'assegnazione del sorgente.
Un altro utilizzo molto comune di JavaScript è la gestione
dei moduli, elementi che ben descrivono il concetto di un oggetto con
proprietà e funzioni. Prendiamo un semplice modulo
anagrafico, simile a tanti presenti in rete.
<form name="anagrafici" action="mailto:user@email"> Nome: <input type="text" name="nome" value="Il tuo nome"><br> Cognome: <input type="text" name="cognome" value="Il tuo cognome"><br> Eta': <input type="text" name="anni" size="3" value="42"><br> Invia: <input type="submit" name="invio" value="invia dati"> </form>
Questo segmento HTML è visto da JavaScript come un oggetto
di tipo "form" con proprietà e metodi. Anche in questo caso
possiamo riferirci all'oggetto tramite array ("document.forms[]")
oppure, preferibilmente, con il suo nome: "document.anagrafici".
Purtroppo questa volta è V3 ad abbandonarci, non supportando
ancora alcuna forma di riferimento ai moduli.
I moduli sono composti da una serie di oggetti che rappresentano i vari
elementi. Ogni elemento ha delle proprietà (generalmente
modificabili), degli eventi ad esso associabili e, talvolta, dei metodi.
Partiamo dal primo elemento del modulo, "nome". E' di tipo testuale e,
fra le altre, ha la proprietà "value", contenente il valore
preimpostato o quello inserito dall'utente e che può essere
modificato tramite assegnazione diretta. Esempio:
alert(document.anagrafici.nome.value); document.anagrafici.nome.value="Pippo";
Non solo è possibile accedere ai vari elementi di un modulo, è anche consentito consultare o modificare le proprietà "method" (metodo di invio "GET" o "POST") e "action" (URL di invio). Questo permette di creare singoli moduli per diverse destinazioni (ad esempio un modulo di ricerca il cui campo "action" è automaticamente modificato a seconda del motore scelto dall'utente). Esempio:
alert(document.anagrafici.action); document.anagrafici.action="mailto:utente2@email";
Fra i metodi disponibili troviamo "reset()" (attualmente non implementato su IB2.1) e ”submit()" che consentono rispettivamente di riportare i contenuti del modulo ai valori preimpostati o effettuare l'invio del modulo stesso proprio come se l'utente avesse premuto il relativo bottone. Esempio:
document.anagrafici.reset(); document.anagrafici.submit();
Nel CD allegato sono presenti altri esempi, relativi sia all'utilizzo degli oggetti messi a disposizione da JavaScript, sia alla creazione di propri oggetti. La manipolazione degli oggetti è un concetto fondamentale per la comprensione di JavaScript, appreso il quale diventa relativamente semplice capire i meccanismi che regolano anche le operazioni più complesse.
Ringraziamenti e note
Si ringraziano AmiTrix development per AWeb e Vapor (nella persona di Luca Danelon) per Voyager3. Grazie ad Angelo Verdone e Daniele Franza per la "prova su strada" del corso.
Ricordiamo che, per ragioni di spazio, gli esempi proposti non contengono tutti gli elementi HTML il cui uso è normalmente obbligatorio all'interno di un documento.