JavaScript è un linguaggio di scripting utilizzato comunemente in ambito web per la creazione di effetti dinamici interattivi, tramite funzioni di script invocate da eventi innescati dall'utente sulla pagina web in uso (mouse, tastiera, caricamento della pagina ecc.).
Nello specifico, si può definire come un linguaggio interpretato, nel senso che il codice non viene compilato, ma eseguito direttamente: la sintassi è relativamente simile a quella del C, C++ e di Java. Si tratta quindi di un linguaggio di programmazione con paradigma ad oggetti e tipizzazione debole, perché non impone regole severe per definire le variabili.
Considerato però il peso crescente che ha questo strumento, anche al di fuori del web, è opportuno scoprirne le nozioni sintattiche di base ed esplorare concetti più evoluti, che nel tempo si sono aggiunti allo standard del linguaggio, che è in costante trasformazione.
- Gli elementi base del linguaggio
- Cosa sono i controlli di flusso e a cosa servono
- Introduzione alle funzioni
- Funzioni predefinite e avanzate
- Javascript: cosa sono gli oggetti
- Come attivare Javascript e le API
- I principali oggetti di Javascript
- Cos'è il Design Pattern e a cosa serve
- Il web storage con Javascript
-
0. Gli elementi base del linguaggio
Shutterstock
Il codice JavaScript è composto da una sequenza di istruzioni interpretata ed eseguita dall'engine, ciascuna delimitata da un punto e virgola (;). Da notare che JavaScript è case sensitive, nel senso che fa distinzione tra maiuscole e minuscole nei nomi di istruzioni, variabili e costanti, senza evidenziare alcun errore.
Nel codice è possibile inserire commenti che non verranno presi in considerazione dall'interprete, usando il commento a singola riga (inline //) oppure il commento multiriga (multiline /* e */). Gli spazi bianchi possono essere utilizzati per aumentare la leggibilità del codice, tranne che per gli spazi all'interno delle stringhe.
JavaScript prevede cinque tipi di dati primitivi, numeri, stringhe, booleani, null e undefined, e un tipo di dato complesso, gli oggetti. Tutti gli altri elementi come array, espressioni regolari, funzioni, sono oggetti. Anche i tipi di dati "primitivi" hanno degli oggetti corrispondenti con relative proprietà e metodi.
Una stringa è una sequenza di caratteri delimitata da doppi (“_”) o singoli (‘_’) apici. L’importante è che il delimitatore finale coincida a quello iniziale. Per inserire caratteri speciali all'interno di una stringa si fa ricorso al carattere di escaping \ (backslash).
JavaScript ha un unico tipo di dato numerico: non c'è distinzione formale tra intero e decimale (per cui serve il punto). Tra i valori numerici speciali: NaN, Not a Number; null; undefined; booleano.
Le variabili servono a memorizzare valori o oggettidurante l'esecuzione degli script. Lavorando in strict mode, riceviamo una segnalazione di errore quando non dichiariamo le variabili così da prevenire eventuali futuri malfunzionamenti.
Un'espressione è una combinazione di valori, variabili ed operatori che che rappresentano un nuovo valore. Gli operatori possono essere aritmetici; relazionali; logici; sui bit o bitwise; condizionali; di concatenazione.
Considerate come matrici matematiche a una o più dimensioni, gli array consentono di associare ad un unico nome di variabile (o identificatore) più valori, accessibili tramite un indice numerico che parte da zero. In genere, i valori contenuti in un array hanno una qualche affinità e il loro uso semplifica lo svolgimento di operazioni cicliche su tutti i valori.
-
1. Cosa sono i controlli di flusso e a cosa servono
Shutterstock
Il controllo di flusso rappresenta l’ordine con cui le istruzioni sono eseguite all’interno di un programma. Quest’ordine, in alcuni casi, può subire variazioni da specifiche strutture dette “di controllo”, che modificano il flusso di esecuzione del codice attraverso condizioni logiche che tipicamente restituiscono un valore booleano (true o false), oppure delle iterazioni (o loop) che continuano finché la condizione non sarà false.
Le istruzioni condizionali consentono di eseguire blocchi di codice alternativi in base ad una condizione.
La forma if esegue un blocco di codice solo se una condizione è vera; l'if...else prevede l’esecuzione di un blocco di codice oppure un altro in base al valore della condizione; l'if..else if...else o if a cascata mette a disposizione più alternative di esecuzione.
Un'altra categoria di istruzioni riguarda le iterazioni o cicli che permettono di eseguire specifiche operazioni (blocchi di codice) in loop N volte, dove N è un numero definito nel caso del ciclo for oppure che potrebbe ripetersi anche all’infinito come nel caso del while finché l’istruzione di controllo (condizione booleana) rimane vera.
In generale, il while è da utilizzare nei casi in cui non sappiamo quando il loop debba terminare. E mentre il while controlla subito se la condizione è vera o falsa, il do-while fa il controllo solo dopo aver eseguito il blocco di istruzioni almeno una volta.
Esistono istruzioni molto più avanzate per gestire loop in JavaScript, ad esempio nel caso di un array si può optare per il forEach e nel caso di un oggetto metodi nativi come Object.keys() (introdotto con ES6) oppure il classico for...in.
-
2. Introduzione alle funzioni
Shutterstock
Una funzione è un insieme di istruzioni racchiuse in un blocco di codice, che può essere contraddistinto da un nome, può accettare argomenti o parametri di ingresso e restituire valori. Se la funzione ha un nome, servirà come riferimento per richiamare ed eseguire la funzione stessa, in qualunque punto del programma.
Una volta dichiarata, la funzione non viene eseguita subito. Stiamo dicendo all'engine JavaScript che al blocco di codice indicato viene assegnato un nome. L'esecuzione vera e propria avviene con l'invocazione o chiamata. Gli eventuali valori inseriti nella chiamata di una funzione vengono passati, cioè assegnati, ai corrispondenti argomenti della definizione della funzione.
Nota bene: riutilizzare il nome di una funzione predefinita o già definita in precedenza annulla la definizione precedente rimpiazzandola con la nuova.
ECMAScript 6 arricchisce la flessibilità della gestione degli argomenti come la possibilità di specificare valori di default. Altra novità introdotta, è la possibilità di specificare il rest parameter: una notazione speciale per indicare un elenco indefinito di argomenti aggiuntivi.
-
3. Funzioni predefinite e avanzate
Shutterstock
JavaScript dispone di alcune funzioni predefinite utili in alcune attività e invocabili in qualsiasi punto dello script: parseInt() e parseFloat() convertono una stringa rispettivamente in un valore numerico intero e decimale; isNaN() prende un argomento e restituisce true se il suo valore è NaN, false altrimenti; isFinite() restituisce true se il valore del suo argomento è diverso da Infinity e da NaN.
Quando una stringa rappresenta un URI: encodeURI() esclude dalla codifica i caratteri , /?:@&=+$#; la controparte decodeURI() restituisce la stringa decodificata. La funzione encodeURIComponent() codifica anche i caratteri speciali esclusi dalla encodeURI(); la corrispondente funzione per la decodifica è decodeURIComponent().
Poiché le funzioni JavaScript sono oggetti di prima classe, possono essere passate come parametri di un'altra funzione, note come callback.
Un nuovo tipo di funzione introdotta dalle specifiche ES6 sono le arrow function: funzioni anonime con una sintassi concisa ed alcune specifiche caratteristiche. Si prestano bene ad essere utilizzate come callback. Rispetto alle funzioni standard, non possono essere utilizzate per la definizione di metodi di un oggetto.
-
4. Javascript: cosa sono gli oggetti
Shutterstock
Un oggetto in JavaScript è un contenitore di valori eterogenei, cioè di elementi caratterizzati da un nome ed un valore. Normalmente, un oggetto è utilizzato per rappresentare un'entità specifica come ad esempio una persona, un ordine, una fattura, una prenotazione, ecc. tramite un'aggregazione di dati e di funzionalità.
Appare come una sorta di array associativo che è possibile costruire e modificare dinamicamente. Per i nomi delle proprietà di un oggetto non ci sono le restrizioni dei nomi delle variabili.
Per accedere ai valori memorizzati in una proprietà di un oggetto possiamo utilizzare la dot-notation in base alla quale indichiamo un oggetto e la proprietà a cui siamo interessati separandoli con un punto.
A differenza delle proprietà di un oggetto che rappresentano dati,i metodi rappresentano attività che un oggetto può compiere. Da notare che non assegniamo alla proprietà il risultato della chiamata alla funzione, ma la funzione stessa tramite il suo nome.
Ogni oggetto, predefinito o meno che sia, è costruito su Object e questo fa sì che tutti gli oggetti JavaScript abbiano alcune caratteristiche comuni.
L'oggetto Object è anche in grado di generare istanze di oggetti a partire da una qualunque espressione JavaScript. Per ogni tipo di dato primitivo, tranne null e undefined, esiste un corrispondente oggetto specializzato che mette a disposizione specifiche proprietà e metodi.
Reflect, introdotto da ECMAScript 2015 (ES6), consente di eseguire operazioni di reflection sugli oggetti, cioè di analizzare e manipolare le loro proprietà. Un nuovo tipo di dato primitivo a fianco ai sei tradizionali è la funzione Symbol() che crea un valore univoco. Il confronto tra due simboli generati restituisce sempre il valore false, ad indicare che non è possibile creare due simboli identici.
Per approfondimenti: Programmazione a oggetti, cos'è e come funziona
-
5. Come attivare Javascript e le API
Shutterstock
JavaScript richiede un programma ospite, che carica ed esegue lo script. L’esempio tipico è quello del browser. Quando viene visitata una pagina web che contiene codice JavaScript, quest’ultimo viene eseguito dall’interprete contenuto nel browser. Le interfacce che consentono al codice di rapportarsi con un browser sono chiamate DOM (Document Object Model, in italiano Modello a Oggetti del Documento).
Il DOM fornisce una rappresentazione del documento come una composizione gerarchica di oggetti, spesso chiamata DOM tree: un albero di oggetti pensato per essere accessibile tramite JavaScript non soltanto in lettura, ma anche per poter cambiare dinamicamente la sua struttura, il contenuto e lo stile.
In ambito web, JavaScript viene usato per scrivere piccole funzioni integrate nelle pagine HTML che interagiscono con il DOM del browser per compiere. Non esiste solo il browser, però. Altri programmi hanno dei piccoli script scritti con questo linguaggio come Adobe Acrobat/Adobe Reader nei loro file PDF o ad esempio Mozilla Firefox, che li utilizza per l’interfaccia utente.
Se l'ambito principale e più noto è quello Web, in cui il sistema ospite è il browser, è vero che possiamo utilizzare JavaScript anche in ambienti diversi.
Infatti, è possibile interfacciarsi con ciascuno grazie alle relative API (Application Programming Interface): costrutti che consentono agli sviluppatori di creare funzionalità complesse più facilmente.
Le API del browser sono integrate nel browser web, espongono i dati dal browser e dall'ambiente del computer circostante e semplificano attività complesse. L’API Web Audio fornisce costrutti JavaScript per manipolare l'audio nel browser: prendere una traccia audio, modificarne il volume, applicarvi effetti, ecc. In background, il browser sta utilizzando un codice complesso di livello inferiore (ad es. C++ o Rust) per eseguire l'effettiva elaborazione dell'audio. Ma ancora una volta, questa complessità viene sottratta dall'API.
Le API di terze parti non sono integrate nel browser per impostazione predefinita e in genere è necessario recuperare il codice e le informazioni da qualche parte sul Web. Ad esempio, l'API di Twitter fornisce un insieme speciale di costrutti per interrogare il servizio Twitter e restituire informazioni specifiche, consentendo per esempio di visualizzare gli ultimi tweet sul sito web.
-
6. I principali oggetti di Javascript
Shutterstock
Vediamo ora una panoramica dei principali oggetti di Javascript da utilizzare per iniziare a muovere i primi passi nella programmazione con questo linguaggio.
Oggetto Window e DOM
L'oggetto principale per l'interazione con il browser è window: una finestra che contiene un documento HTML. Ciascuna finestra o tab ha associato un proprio oggetto window e a ciascun frame definito in una pagina HTML corrisponde un oggetto window.
Questo oggetto, oltre ad identificare l'elemento visivo del browser, rappresenta il contesto di esecuzione globale per JavaScript, cioè l'oggetto all'interno del quale vengono definite variabili e funzioni globali.
Qualsiasi variabile o funzione definita nel contesto globale diventa di fatto proprietà o metodo dell'oggetto window.
Tra i metodi: alert() visualizza una finestra modale con un messaggio ed un pulsante OK; confirm() visualizza una finestra modale con un messaggio e due pulsanti (uno per la conferma e uno per l'annullamento) e restituisce un valore booleano che rappresenta true o false; prompt() richiede l'inserimento di un valore che viene catturato e restituito dal metodo; open() apre una nuova finestra o tab.
L'oggetto window fornisce anche alcuni meccanismi per gestire e controllare la navigazione dell'utente: history, che tiene traccia della navigazione e location che permette di gestire l'URL corrente.
Per ottenere informazioni sul browser corrente e su alcune sue impostazioni possiamo utilizzare la proprietà navigator che fornisce informazioni per identificare il browser e il sistema operativo su cui è in esecuzione, ma non sempre le informazioni sono così utili ed accurate. Anche la proprietà appName, che dovrebbe restituire il nome del browser, restituisce valori non sempre attinenti.
Un’altra delle proprietà dell'oggetto window è document che rappresenta il documento HTML caricato nella finestra corrente e la struttura di questo oggetto, nota con il nome di DOM. Per visualizzare la struttura ad albero di un documento si può utilizzare uno degli strumenti di ispezione integrati o comunque disponibili nei browser più recenti.
Il metodo getElementById() restituisce un oggetto che rappresenta il nodo di tipo elemento che ha l'attributo id con il valore specificato. Analogo è il metodo getElementsByName(), che restituisce l'elenco dei nodi della pagina il cui valore dell'attributo name corrisponde a quello del parametro. A differenza del primo, questo metodo restituisce un elenco di oggetti, ovvero un NodeList, cioè una struttura dati simile ad un array contenente nodi del DOM.
È possibile individuare gli elementi di una pagina in base al loro tag utilizzando il metodo getElementsByTagName() che restituisce sotto forma di NodeList l'elenco dei nodi corrispondenti al tag specificato come parametro. Con il metodo getElementByClassName() si ottiene l'elenco dei nodi a cui è stato assegnato un determinato valore come attributo class.
Tra le novità introdotte più di recente nelle specifiche del DOM c'è la possibilità di selezionare gli elementi di una pagina utilizzando i selettori CSS: querySelector() che restituisce il primo elemento trovato e querySelectorAll(), l'elenco di tutti gli elementi individuati dal selettore.
Una volta individuato l'elemento o gli elementi presenti su una pagina, possiamo modificarne il contenuto sfruttando proprietà e metodi specifici dei nodi di tipo elemento. Alcuni metodi del DOM ci consentono di analizzare e muoverci all'interno della struttura di un documento.
Oggetto Event
Oltre ad essere organizzato a oggetti e metodi, JavaScript sfrutta la presenza degli eventi: è qualcosa che accade nel documento in parte dovuto al verificarsi di una certa interazione dell'utente (passaggio del mouse su un link, click su qualcosa...), altre volte alle sollecitazioni che provengono da altre applicazioni o dal sistema stesso (la pagina è stata caricata).
Per intercettare gli eventi che vengono scatenati, utilizziamo il meccanismo degli handler (o listener): una funzione di callback che viene associata ad un certo evento.
La funzione addEventListener() è un metodo esposto dagli elementi del DOM e rappresenta la più comune tra le modalità usate per associare un evento al rispettivo handler, consente di definirne e gestirne più di uno per lo stesso evento e funziona con qualunque elemento del DOM (non solo con gli elementi HTML).
Altro vantaggio: possiamo rimuovere l'associazione tra evento e handler utilizzando la funzione removeEventListener che prende gli stessi parametri di addEventListener ma ha la funzione opposta.
La proprietà target rappresenta l'elemento su cui si è verificato l'evento, in maniera indipendente da altri fattori come ad esempio il flusso degli eventi e quindi con maggiori garanzie rispetto all'oggetto this.
Insieme all'elemento su cui si è verificato l'evento possiamo individuare anche il tipo di evento tramite la proprietà type.
Accedere a un form
Un form è un componente di una pagina Web che, tramite elementi speciali detti controlli, consente all'utente di inserire dati da inviare al server per l'elaborazione. I controlli sono l'insieme degli elementi che consentono l'immissione di dati, la selezione di valori o l'avvio di funzionalità da parte dell'utente, come ad esempio caselle di testo, checkbox, radio button, pulsanti e simili.
Per form semplici, il processo di raccolta ed invio dei dati al server può essere effettuato senza la necessità di coinvolgere JavaScript, soprattutto con l'introduzione delle nuove funzionalità di HTML5 che prevedono una prima validazione dei dati inseriti dall'utente.
Tuttavia, per avere un certo controllo sui dati e soprattutto se l’elaborazione deve avvenire sul client è necessario ricorrere a JavaScript.
Durante la generazione del DOM viene popolato un array contenente l'elenco degli oggetti che rappresentano i form presenti nella pagina. Questo array è accessibile tramite la proprietà forms dell'oggetto document. L'approccio migliore è quello di assegnare al form un identificatore tramite l'attributo id oppure un nome tramite l'attributo name.
Un altro modo per accedere a un form cui è stato assegnato un nome consiste nell'utilizzare il metodo getElementsByName() che consente di accedere a qualsiasi elemento a cui è stato assegnato un nome tramite l'attributo name.
Da notare che, mentre l'attributo id è utilizzato per identificare un elemento nel DOM e pertanto non dovrebbero esistere più elementi con lo stesso id, è possibile avere più elementi con lo stesso valore per l'attributo name. Per questo motivo il metodo getElementsByName() restituisce un array di oggetti.
Ciascun oggetto form contiene un array in cui sono contenuti i suoi controlli a cui è possibile accedere tramite indice utilizzando l'oggetto form. Anche per i controlli è possibile sfruttare l'attributo name ed accedere ad essi come abbiamo visto per le form.
Oggetto Image
All'interno di una pagina HTML, JavaScript è in grado di manipolare immagini a diversi livelli di complessità. Le recenti tecnologie legate agli sviluppi di HTML5, consentono non solo di gestire immagini già pronte, ma di generare e modificare grafica dinamicamente.
L'approccio più elementare per gestire un'immagine consiste nella manipolazione dell'elemento "img" dell'HTML: un'immagine statica sulla pagina che non ha bisogno di elaborazione da parte di JavaScript. Gestendo tramite JavaScript l'elemento "img" possiamo realizzare semplici funzionalità come ad esempio la navigazione tra un elenco di immagini.
È possibile creare un elemento immagine da aggiungere al DOM utilizzando il costruttore Image(): approccio analogo alla creazione di un elemento "img", ma comodo per il pre caricamento di immagini.
Il caricamento di ogni immagine avviene nel momento in cui assegniamo il nome del file all'attributo src. Ciò può comportare un'attesa da parte dell'utente, specie se le dimensioni dell'immagine sono non trascurabili. La creazione di un oggetto Image fa sì che l'immagine corrispondente venga caricata nella cache del browser senza essere visualizzata sulla pagina.
-
7. Cos'è il Design Pattern e a cosa serve
Shutterstock
I Design Pattern sono soluzioni tecniche a problemi comuni di progettazione del software: schemi logici di risoluzione di un problema riusabili e indipendenti dal linguaggio di programmazione che offrono un modello di riferimento per la realizzazione di componenti software facilmente manutenibili.
Possiamo raggrupparli in tre categorie: i pattern creazionali si occupano della creazione di classi e oggetti; i pattern strutturali aiutano a gestire le relazioni tra gli oggetti, per rendere scalabile l'architettura di un'applicazione; i pattern comportamentali si focalizzano sulla comunicazione tra gli oggetti di un'applicazione.
-
8. Il web storage con Javascript
Shutterstock
Tra le limitazioni storiche di JavaScript c'era l'impossibilità di memorizzare i dati in maniera persistente. Gli unici due approcci disponibili sfruttavano i cookie per la persistenza locale e il server per quella remota. Ma mentre il primo approccio ha delle limitazioni sia in quantità di dati memorizzabili che in flessibilità di accesso, il secondo prevede la presenza di un backend lato server che si occupi dell'effettiva persistenza e presuppone di essere online. Le cose poi sono cambiate, anche grazie all'avvento di HTML5.
JavaScript dispone di una serie di API che permettono di gestire dati in maniera più flessibile e senza intermediari. Il Web Storage offre un approccio semplice e lineare nella gestione dei dati locali, superando i limiti storici dei cookie, mediante il quale un'applicazione JavaScript può memorizzare dati localmente nel browser.
A differenza dei cookie, il Web Storage mette a disposizione maggior spazio disco, intorno ai 5 MB, e le informazioni non vengono mai trasferite al server.
Tuttavia, come per i cookie, viene mantenuta la same origin policy in base alla quale soltanto gli script che provengono dallo stesso dominio possono accedere allo stesso Web Storage. La persistenza dei dati non è però strutturata e le stringhe rappresentano l'unico tipo di dati consentito. Inoltre, in presenza di grandi quantità di dati si può assistere ad un calo delle prestazioni sia in lettura che in scrittura. Rappresenta comunque una buona soluzione nella maggior parte delle situazioni in cui l'accesso a dati persistenti non rappresenta l'attività principale dell'applicazione.
Per approfondimenti: A cosa servono cache e cookie