JavaScript possiede cinque tipi di dati primitivi:
Undefined
Null
Boolean
Number
String
Un Boolean e' un oggetto che consiste di un valore vero o falso. Un esempio potrebbe essere:
Un Number e' un insieme di cifre numeriche che rappresentano un numero. Ad esempio:
Una Stringa, infine, e' un insieme di zero o piu' caratteri:
Typeof
Se c'e' un operatore poco conosciuto in JavaScript, questo e' sicuramente typeof. Typeof ci dice il tipo di dati con cui stiamo lavorando. Proviamo a vedere un esempio:
Oggetti
Un oggetto e' una collezione di proprieta' (properties). Queste ultime possono essere sia tipi di dati primitivi, sia oggetti e funzioni. In quest'ultimo caso prendono il nome di metodi e li vedremo per esteso piu' in la' in quest'articolo. Una funzione costruttore (o piu' semplicemente, costruttore) e' una funzione usata per creare un oggetto. JavaScript possiede molti oggetti built-in come Array, Image, Date, etc. Molti di voi saranno sicuramente familiari con gli oggetti Image, utili per creare effetti di roll-overing molto efficaci. Ad esempio, quando usiamo il codice:
Abbiamo creato un nuovo oggetto Image ed assegnato una property a questo nuovo oggetto: la proprieta' src. Image1 e' un'istanza dell'oggetto Image. Utilizzando la struttura puntata (.) di JavaScript, il codice sopra accede e setta la proprieta' src del nostro nuovo oggetto. Ma come creare le proprie funzioni?
Nel codice sopra abbiamo appena creato un nostro oggetto. myFunc() e' una funzione costruttore. A questo punto, potremmo chiederci come riesce JavaScript a capire quando e come creare un'istanza dell'oggetto myFunc, invece di ritornare il valore della funzione chiamata. Proviamo a confrontare il codice sopra con il seguente:
In questo caso abbiamo assegnato il valore 5 a myObject. Dove sta la differenza tra questi due codici? La risposta e' la parola chiave: new. New dice a JavaScript di creare un oggetto seguendo i passi esplicitati nel corpo della funzione costruttore myFunc. Quando creiamo l'oggetto Image, ad esempio, facciamo la stessa cosa usando il costruttore built-in di JavaScript per l'oggetto Image, anziche' un nostro costruttore personale.
Adesso sappiamo come creare una funzione costruttore ed un oggetto attraverso il suo costruttore. Nel nostro esempio, abbiamo creato il costruttore myFunc() e creato un'istanza dell'oggetto, assegnandola alla variabile myObject. Tutto carino, certo, ma dove sta il punto? Tanto per cominciare, l'oggetto myObject, come il suo padre Image, puo' avere delle properties:
Nel codice sopra abbiamo creato una property per il nostro oggetto. Purtroppo, l'approccio sopra soffre di un grave problema. Se creiamo una nuova istanza dell'oggetto myFunc, dovremo riassegnare la proprieta' StringValue alla nuova istanza appena creata. Ad esempio:
Come possiamo creare delle proprieta' comuni per tutti gli oggetti? La risposta risiede all'interno della funzione costruttore myFunc(). La parola chiave this, all'interno del costruttore, si riferisce all'oggetto che stiamo creando. Ad esempio:
Adesso tutti gli oggetti myFunc avranno una proprieta' chiamata StringValue, assegnata con il valore iniziale "This is a String". Ogni oggetto, ovviamente, potra' continuare ad avere il suo valore distintivo per la proprieta' sopra indicata. In altre parole, una volta definita', possiamo cambiare il valore della proprieta' stessa senza intaccare le altre istanze:
Possiamo ottenere un risultato simile, utilizzando i parametri per il costruttore:
Nel costruttore di myFunc(), this.StrinValue si riferisce alla proprieta' che stiamo assegnando al nuovo oggetto appena creato, mentre StringValue si riferisce alla variabile locale della funzione passata come argomento. E per i metodi?
In aggiunta alle proprieta', gli oggetti possono avere dei metodi. Il metodo di un oggetto e' una funzione che puo' essere eseguita dall'oggetto stesso (una sua istanza). Proviamo a vederne un esempio. Creiamo un oggetto Circle. Per fare questo, dobbiamo definirne le funzioni e quindi renderle metodi del nostro nuovo oggetto.
Adesso definiamo alcune funzioni utili:
Attenzione ad un particolare: a cosa si riferisce this.radius? this si riferisce sempre all'oggetto corrente. Nel nostro caso: l'oggetto Circle. Quindi, this.radius, si riferirisce alla proprieta' radius dell'oggetto Circle. Come aggiungiamo queste funzioni ai nostri oggetti? Non e' molto difficile. Cambiamo il nostro costruttore:
Il codice sopra assegna le funzioni getArea e getCircumference all'oggetto Circle, rendendole a tutti gli effetti dei metodi proprietari dell'oggetto. Possiamo usare i metodi come normali funzioni. Per farlo, dobbiamo prima accedere all'oggetto nel quale si trova incapsulato il metodo:
Molto interessante, certo. Ma se volessimo integrare tutto all'interno della funzione stessa? Esistono vari modi per ottenere questo scopo. Ad esempio, attraverso le funzioni interni. Una funzione interna e' una funzione all'interno della funzione. Carino, vero?
E' lo stesso codice visto sin'ora, ad eccezione delle funzioni che risultano spostate. Dal momento che le funzioni interne possono accedere alla variabili locali, all'interno delle nostre due funzioni, al posto di this.radius, potremmo usare direttamente radius. Semplicemente, dovrebbe essere possibile accedere alla variabile locale radius passata come argomento al costruttore Circle. Il nostro codice, quindi, potrebbe diventare qualcosa di questo tipo:
Ok. Adesso cambiamo il valore di radius di un oggetto e calcoliamone l'area:
Attenzione! C'e' qualcosa di strano! Il valore ritornato e' 31400, al posto di 7850. Dove stiamo sbagliando? radius si riferisce al valore che abbiamo passato alla funzione costruttore, non al valore dell'oggetto. Quindi, quando cambiamo il raggio dell'oggetto, i metodi getArea e getCircumference, mantengono ancora il vecchio valore del raggio (quello calcolato una 10ina di esempi precedenti). Ecco perche' non possiamo usare semplicemente la variabile radius ma dobbiamo mantenerne la referenza all'oggetto corrente con this.
Esistono tre categorie di oggetti in JavaScript: Nativi, Host Objects e definiti dall'utente.
Gli oggetti nativi sono quegli oggetti forniti da JavaScript. Esempi di questi oggetti sono String, Number, Array, Image, Date, Math, etc.
Gli oggetti Host sono oggetti che sono forniti a JavaScript dall'ambiente browser. Esempi di questi oggetti sono window, document, forms, etc.
Infine, gli oggetti definiti dall'utente sono quegli oggetti definiti dal programmatore.
Uno dei concetti fondamentali in JavaScript e' che ogni elemento che puo' ospitare proprieta' e metodi e' un oggetto, eccezion fatta per i tipi di dati primitivi. Possiamo usare i costruttori built-in di JavaScript per creare nuovi oggetti:
Sopra, abbiamo creato un nuovo oggetto Image usando il costruttore nativo di Image con le seguenti proprieta':
width = 50
height = 100
src = "myDog.gif"
A questo oggetto base possiamo aggiungere metodi e proprieta'. Ogni oggetto in JavaScript deriva dall'oggetto base Object. Proviamo a dare un occhiata da vicino alla primitiva String:
Ovviamente, possiamo rendere una stringa un oggetto, usando il suo costruttore:
Adesso, abbiamo creato un'oggetto String. Possiamo fare lo stesso con Number e Boolean. Ma perche' dovremmo volerlo? Una volta resi oggetti, potremmo aggiungere delle proprieta' distintive per ogni oggetto. Un tipo primitivo, contiene proprieta' e metodi che gli sono stati assegnati in fase di costruzione, ma non puo' contenere proprieta' o metodi personali.
Cosi', una stringa contiene la properita' length e tanti metodi definiti nel tipo nativo String(), ma non puo' contenere proprieta' e metodi specializzati.
In questo modo abbiamo creato un oggetto Number ed abbiamo definito un metodo doubleIt(). Il tipo di myNumber adesso e' diventato "object". Oggetti evoluti sono in grado di mantenere al loro interno proprieta' uniche e metodi. I dati primitivi come String, Boolean, Number, Undefined e Null, non possono farlo. Questa e' forse la piu' grande differenza tra i tipi primitivi e gli oggetti.