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.