Introduzione
Perché una re-introduzione? Perché è ragionevole ritenere che JavaScript sia il linguaggio di programmazione meno compreso del mondo. Spesso deriso come un giocattolo, dietro la sua ingannevole semplicità si celano alcune caratteristiche molto potenti. Il 2005 ha visto il lancio di un certo numero di applicazioni JavaScript di alto profilo, mostrando che una più profonda conoscenza di questa tecnologia è requisito importante per ogni sviluppatore web.
Può essere utile cominciare facendoci un'idea della storia di questo linguaggio. JavaScript è stato creato nel 1995 da Brendan Eich, uno sviluppatore della Netscape, e fu inizialmente rilasciato con Netscape 2 all'inizio del 1996. La sua designazione doveva essere originariamente LiveScript, ma il suo nome fu cambiato con una malaugurata decisione di marketing, cercando di sfruttare la popolarità del linguaggio Java della Sun Microsystems, a dispetto del fatto che i due linguaggi avessero veramente poco in comune. Ciò è stato da allora fonte di confusione.
Microsoft rilasciò una versione sostanzialmente compatibile del linguaggio alcuni mesi dopo, la chiamò JScript e la rilasciò con IE 3. Netscape inviò le specifiche del linguaggio alla Ecma International, un'organizzazione europea per gli standard, che rilasciò la prima edizione dello standard ECMAScript nel 1997. Lo standard ricevette un aggiornamento significativo con la pubblicazione della sua terza edizione (ECMAScript edition 3) nel 1999, che è rimasta sostanzialmente immutata sino ad oggi, anche se attualmente l'edizione 4 è in fase di lavorazione.
Questa stabilità è una grande novità per gli sviluppatori, dato che ha dato il tempo alle varie implementazioni di tenere il passo. In questo articolo focalizzerò l'attenzione quasi esclusivamente sul dialetto della terza edizione. Per familiarità, continuerò a riferirmi al linguaggio con il termine JavaScript.
A differenza della maggior parte dei linguaggi di programmazione, JavaScript non ha i concetti di input e output. E' concepito per funzionare come linguaggio di scripting in un ambiente host, e il compito di fornire dei meccanismi per la comunicazione con il mondo esterno spetta a questo ambiente host. Il più comune ambiente host è il browser, ma possiamo trovare interpreti JavaScript anche in Adobe Acrobat, in Photoshop, nel motore degli Yahoo! Widget, e altri software.
Panoramica
Inizieremo dando un'occhiata all'aspetto fondamentale di ogni linguaggio: i tipi. I programmi JavaScript manipolano dei valori, e questi valori appartengono tutti a un tipo. I tipi in JavaScript sono:
Abbiamo poi i tipi Undefined e Null, che sono alquanto strani, gli array, che sono un particolare tipo di oggetto, le date e le espressioni regolari, che sono tipi aggiuntivi che JavaScript ci fornisce. Inoltre, per essere tecnicamente accurati, in JavaScript le funzioni sono un particolare tipo di oggetto. Il diagramma dei tipi in JavaScript è quindi il seguente:
- Number (Numeri)
- String (Stringhe)
- Boolean (Booleani)
- Object (Oggetti)
- Function (Funzioni)
- Array
- Date (Date)
- RegExp (Espressioni Regolari)
- Null
- Undefined
Ci sono anche inoltre alcuni tipi predefiniti di errori, ma le cose sono molto più semplici se manteniamo il nostro diagramma così com'è.
Numeri
Secondo le specifiche, i numeri in JavaScript sono dei "valori a 64 bit a doppia precisione nel formato IEEE 754". Ciò ha interessanti conseguenze. In JavaScript non ci sono numeri interi, quindi bisogna prestare attenzione con le operazioni aritmetiche se si è abituati a usare C o Java. Ecco cosa succede in un'operazione come questa:
0.1 + 0.2 = 0.30000000000000004
Gli operatori aritmetici sono supportati e includono l'addizione, la sottrazione, il modulo aritmetico (o resto) e così via. C'è anche un oggetto predefinito che ho dimenticato di menzionare prima chiamato Math e che fornisce costanti e funzioni matematiche più avanzate:
Math.sin(3.5); d = Math.PI * r * r;
E' possibile convertire una stringa in numero intero usando la funzione predefinita parseInt()
. Questa funzione prende la base di numerazione come secondo argomento opzionale, che bisognerebbe sempre passare alla funzione:
> parseInt("123", 10) 123 > parseInt("010", 10) 10
Se la base di numerazione non viene passata alla funzione, questo può portare a risultati strani:
> parseInt("010") 8
Questo accade perché la funzione parseInt
ha deciso di trattare la stringa come numero in base 8, perché c'è uno zero iniziale.
Per convertire un numero in base 2 in numero intero, basta cambiare la base:
> parseInt("11", 2) 3
Un valore speciale chiamato NaN
(abbreviazione per "Not a Number", "Non numerico") viene ritornato se la stringa non contiene un valore numerico:
> parseInt("ciao", 10) NaN
NaN
è "tossico": se esso viene passato in ingresso a qualsiasi operazione aritmentica, il risultato sarà anch'esso NaN
:
> NaN + 5 NaN
E' possibile verificare se è un valore è NaN
usando la funzione predefinita isNaN()
:
> isNaN(NaN) true
JavaScript possiede anche i valori speciali Infinity
e -Infinity
(infinito e meno infinito):
> 1 / 0 Infinity > -1 / 0 -Infinity
Stringhe
In JavaScript le stringhe sono delle sequenze di caratteri. Più precisamente, sono delle sequenze di caratteri Unicode, e ogni carattere è rappresentato con 16 bit. Questa notizia dovrebbe essere benvenuta a chiunque abbia avuto a che fare con l'internazionalizzazione.
Per rappresentare un singolo carattere, basta usare una stringa di lunghezza 1.
Per trovare la lunghezza di una stringa, bisogna accedere alla sua proprietà length
:
> "ciao".length 4
Ecco il nostro primo incontro con gli oggetti JavaScript! Ho già detto che anche le stringhe sono oggetti? Le stringhe hanno anche dei metodi:
> "ciao".charAt(0) c > "ciao, mondo".replace("ciao", "addio") addio, mondo > "ciao".toUpperCase() CIAO
Altri tipi
JavaScript distingue tra null
, che è un oggetto del tipo 'object' e che indica che alla variabile non è stato assegnato deliberatamente un valore, e undefined
, che è un oggetto del tipo 'undefined', che indica un valore non inizializzato, cioè un valore che ancora non è stato nemmeno assegnato. Parleremo successivamente delle variabili, ma in JavaScript è possibile dichiarare una variabile senza assegnarle un valore. Se viene fatto questo, il tipo della variabile è undefined
.
JavaScript possiede il tipo boolean, i cui relativi possibili valori sono true
e false
(ambedue parole chiave del linguaggio). Ogni valore può essere convertito in boolean secondo queste regole:
-
false
,0
, la stringa vuota (""
),NaN
,null
, eundefined
diventano tuttifalse
- tutti gli altri valori diventano
true
E' possibile effettuare questa conversione esplicitamente, usando la funzione Boolean()
:
> Boolean("") false > Boolean(234) true
Ad ogni modo questo è raramente necessario, dato che JavaScript eseguirà silenziosamente questa conversione quando si attende un valore booleano, come per esempio in un costrutto if
(vedi sotto). Per questo motivo, a volte parliamo semplicemente di "valori vero" e "valori falso", riferendoci ai valori che rispettivamente diventano true
e false
, quando convertiti in booleani.
Sono supportate anche operazioni come &&
(and logico), ||
(or logico), and !
(not logico); vedere oltre.
Variabili
In JavaScript le nuove variabili vengono dichiarate usando la parola chiave var
:
var a; var name = "simone";
Se viene dichiarata una variabile senza assegnarle un valore, il suo tipo sarà undefined
.
Operatori
Gli operatori numerici in JavaScript sono +
, -
, *
, /
e %
, che è l'operatore del resto aritmetico. L'operatore di assegnazione è =
, e ci sono anche dei costrutti di assegnamento composto come +=
e -=
, equivalenti all'espressione x = x operatore y
.
x += 5 x = x + 5
E' possibile usare ++
e --
, rispettivamente per incrementare o decrementare un valore. Questi operatori possono essere usati come prefisso o postfisso di un'espressione.
L'operatore +
esegue anche la concatenazione tra stringhe:
> "ciao" + " mondo" ciao mondo
Se sommiamo una stringa a un numero (o a un altro valore), il tutto viene dapprima convertito in stringhe. Questo potrebbe sorprendere:
> "3" + 4 + 5 345 > 3 + 4 + "5" 75
Aggiungere una stringa vuota a un valore non-stringa è un utile metodo per effettuare la conversione in stringa.
I confronti in JavaScript possono essere fatti usando gli operatori <
, >
, <=
e >=
. Questi operatori funzionano sia con le stringhe che con i numeri. Il test di uguaglianza è un po' meno semplice. L'operatore ==
esegue una conversione di tipo se gli vengono passati valori di tipi differenti, il che porta a risultati interessanti come questi:
> "dog" == "dog" true > 1 == true true
Per evitare la conversione di tipo, è possibile usare l'operatore ===
:
> 1 === true false > true === true true
Ci sono anche gli operatori !=
e !==
.
JavaScript ha anche gli operatori bit-a-bit. Se si desidera usarli, sono lì.
Strutture di controllo
JavaScript ha un insieme di strutture di controllo simili a quelle di altri linguaggi della famiglia del C. I costrutti condizionali sono forniti da if
e else
; è possibile concatenare insieme questi costrutti come ci si aspetterebbe:
var nome = "gatti"; if (nome == "cani") { nome += "!"; } else if (nome == "gatti") { nome += "!!"; } else { nome = "!" + name; } nome == "gatti!!"
JavaScript ha i cicli while
e do-while
. Il primo viene usato per eseguire semplici cicli; il secondo per i cicli in cui si vuole essere sicuri che il corpo del ciclo sia eseguito almeno una volta:
while (true) { // un ciclo infinito! } do { var input = ottieni_input(); } while (inputNonValido(input))
Il ciclo for
è lo stesso che troviamo in C e in Java: permette di avere le informazioni di controllo di un ciclo in una singola riga.
for (var i = 0; i < 5; i++) { // Verrà eseguito 5 volte }
Gli operatori &&
e ||
usano la logica del corto circuito, il che significa che valuteranno il loro secondo operando solamente in base al valore del primo. Questo è utile per controllare il valore di oggetti null prima di accedere ai loro attributi:
var nome = o && o.metodo();
o per impostare valori di default:
var nome = altroNome || "default";
JavaScript ha un operatore ternario per costrutti condizionali di una sola riga:
var permesso = (eta > 18) ? "sì" : "no";
Il costrutto switch
può essere usato per scegliere tra diverse alternative, in base a un certo valore:
switch(azione) { case 'disegna': disegnalo(); break; case 'mangia': mangialo(); break; default: non_fare_niente(); }
Se non viene aggiunta la parola chiave break
, l'esecuzione continuerà al livello successivo. Raramente questo è ciò che si vuole, infatti quando si desidera questo comportamento val la pena inserire un commento che specifichi che ciò è intenzionale, allo scopo di rendere più facile il debugging:
switch(a) { case 1: // fallthrough case 2: mangialo(); break; default: non_fare_niente(); }
L'uso della parola chiave default
è opzionale. E' possibile inserire espressioni sia nella parte switch che nella parte case; i confronti avvengono tra le due espressioni usando l'operatore ===
:
switch(1 + 3): case 2 + 2: yay(); break; default: non_accade_nulla(); }
Oggetti
Gli oggetti JavaScript sono semplicemente delle collezioni di coppie nome-valore. In quanto tali, sono simili a:
- Dizionari in Pythn
- Hash in Perl e in Ruby
- Tabelle di hash tables in C e in C++
- HashMaps in Java
- Array associativi in PHP
Il fatto che questa struttura dati sia tanto largamente usato è un'attestazione della sua versatilità. Visto che tutto (eccetto i tipi 'core') in JavaScript è un oggetto, qualsiasi programma JavaScript comporta l'avere a che fare con ricerche in tabelle di hash. E' una buona cosa che esse siano così veloci!
La parte del "nome" è una stringa JavaScript, mentre il valore può essere qualsiasi valore JavaScript, compresi gli oggetti. Questo permette di costruire strutture di dati di complessità arbitraria.
Ci sono due modi per creare un oggetto vuoto:
var ogg = new Object();
E:
var ogg = {};
Queste due espressioni sono semanticamente equivalenti; la seconda è chiamata sintassi oggetto letterale, ed è più conveniente. Essa non è presente nelle prime versioni del linguaggio, e questo è il motivo per cui è possibile vedere molto codice che usa il vecchio metodo.
Una volta creato un oggetto, si può accedere alle sue proprietà in uno dei due seguenti modi:
ogg.nome = "Simone" var nome = ogg.nome;
E...
ogg["nome"] = "Simone"; var nome = ogg["nome"];
Anche queste due espressioni sono semanticamente equivalenti. Il secondo metodo presenta il vantaggio che il nome della proprietà viene fornito come stringa, il che significa che può essere calcolato a run-time. Questo metodo può essere usato anche per impostare o ottenere proprietà con nomi che sono parole riservate del linguaggio:
ogg.for = "Simone"; // Errore di sintassi ogg["for"] = "Simone"; // funziona
La sintassi dell'oggetto letterale può essere usata per inizializzare interamente un oggetto:
var ogg = { nome: "Carlo", "per": "Max", dettagli: { colore: "arancio", dimensione: 12 } }
L'accesso agli attributi può essere concatenato:
> ogg.dettagli.colore arancio > ogg["dettagli"]["dimensione"] 12
Array
Gli array in JavaScript sono di fatto un tipo speciale di oggetto. Funzionano come normali oggetti (è possibile accedere naturalmente alle proprietà numeriche usando le parentesi quadre []), ma hanno una proprietà magica chiamata 'length
'. Il valore ritornato da questa proprietà è sempre maggiore di uno rispetto all'indice più alto nell'array.
Il vecchio metodo per creare degli array è come segue:
> var a = new Array(); > a[0] = "cane"; > a[1] = "gatto"; > a[2] = "gallina"; > a.length 3
Una notazione più conveniente è quella di usare un array letterale:
> var a = ["cane", "gatto", "gallina"]; > a.length 3
Lasciando una virgola di coda alla fine di un array letterale si ottiene un comportamento imprevedibile di browser in browser, quindi è meglio non usare questa sintassi.
Notare che array.length
non è necessariamente il numero dei valori nell'array. Si consideri la situazione che segue:
> var a = ["cane", "gatto", "gallina"]; > a[100] = "volpe"; > a.length 101
Ricordare: il valore ritornato da length
è il valore dell'indice più alto più uno.
Se si interroga un indice non esistente dell'array, si ottiene undefined
:
> typeof(a[90]) undefined
Se si tiene conto di questo, è possibile fare un'iterazione sull'array in questo modo:
for (var i = 0; i < a.length; i++) { // Fai qualcosa con a[i] }
Questo metodo è un po' inefficiente, perché si sta leggendo la proprietà dell'array a ogni ciclo. Un miglioramento è il seguente:
for (var i = 0, lungh = a.length; i < lungh; i++) { // Fai qualcosa con a[i] }
E ancora meglio:
for (var i = 0, valore; valore = a[i]; i++) { // Fai qualcosa con la variabile 'valore' }
Abbiamo impostato due variabili. L'assegnamento nella parte centrale del ciclo for
viene testata per verificare che produca il valore true
. Se questo accade, il ciclo continua. Visto che i
viene incrementata a ogni ciclo, i valori degli elementi dell'array verranno assegnati a valore
nell'ordine in cui l'array viene attraversato. Il ciclo si ferma quando un valore falso viene trovato (undefined
produce un valore falso quando viene eseguito il test della verità).
Notare che questro trucco dovrebbe essere usato solamente per gli array che non contengono valori false
o valori che potrebbero produrre un valore false
al test della verità (un esempio sono gli array di oggetti o i nodi DOM). Se si sta eseguendo un'iterazione su dati numerici che possono includere il valore 0 o dati stringa che possono includere stringhe vuote, bisogna usare invece la notazione i, j
.
Se si vuole aggiungere un elemento a un array, il modo più sicuro per farlo è come questo:
a[a.length] = elemento;
Visto che a.length
ritorna un valore uguale all'indice più alto più uno, è certo che si starà assegnando un valore a una posizione vuota alla fine dell'array.
Gli array hanno alcuni metodi:
a.toString(), a.toLocaleString(), a.concat(item, ..), a.join(sep), a.pop(), a.push(item, ..), a.reverse(), a.shift(), a.slice(start, end), a.sort(cmpfn), a.splice(start, delcount, [item]..), a.unshift([item]..)
-
concat
ritorna un nuovo array con degli elementi aggiunti ad esso. -
pop
rimuove e ritorna l'ultimo elemento -
push
aggiunge uno o più elementi alla fine dell'array -
slice
ritorna un sotto-array -
sort
prende una funzione opzionale di confronto -
splice
permette di modificare un array cancellando una sezione e rimpiazzandola con altri elementi -
unshift
può essere utilizzata per aggiungere degli elementi all'inizio di un array
...traduzione ancora incompleta...
{{ languages( { "fr": "fr/Une_r\u00e9introduction_\u00e0_JavaScript", "en": "en/A_re-introduction_to_JavaScript" } ) }}