Progettazione Web - JavaScript
Cerca per parola chiave 0/0

JavaScript

Il linguaggio: variabili, funzioni, oggetti, array e classi

HTML descrive il contenuto, CSS l'aspetto: JavaScript dà il comportamento. In questo modulo impariamo il linguaggio; nel prossimo lo useremo per far reagire la pagina. Gli esempi si possono modificare ed eseguire: il risultato compare nella console a destra, la stessa che trovi nel browser premendo F12.

JavaScript e il browser

Codice che gira sul client

JavaScript è un linguaggio interpretato dal browser: il server manda il codice insieme alla pagina e il browser lo esegue sul computer dell'utente. Per questo si dice che è un linguaggio lato client. Il nome è solo un'operazione di marketing del 1995: con Java non ha niente a che fare.

Che cosa permette
  • reagire subito alle azioni dell'utente, senza aspettare il server;
  • modificare la pagina dopo il caricamento;
  • controllare i moduli prima dell'invio;
  • scambiare dati con il server senza ricaricare la pagina;
  • disegnare, animare, usare le API del dispositivo.
Che cosa non garantisce
  • che venga eseguito: l'utente può disattivarlo;
  • che resti segreto: chiunque legge il codice;
  • la sicurezza: tutto ciò che controlla va ricontrollato sul server;
  • che funzioni ovunque allo stesso modo: i browser più vecchi non supportano le novità.

Da Netscape a ECMAScript

JavaScript nasce nel 1995 a Netscape, scritto da Brendan Eich in pochi giorni. Per evitare che ogni browser ne facesse una versione diversa viene standardizzato dall'ente Ecma con il nome di ECMAScript. Le tappe da ricordare:

  • ES5 (2009): la versione che per anni ha funzionato ovunque;
  • ES6, detto anche ES2015: la grande svolta, con let e const, funzioni freccia, classi, moduli, Promise, template literal;
  • da allora esce una versione all'anno (ES2016, ES2017, … ES2025), ognuna con poche aggiunte.

Il programma che esegue il codice si chiama motore: V8 in Chrome ed Edge, SpiderMonkey in Firefox, JavaScriptCore in Safari. Lo stesso V8 è alla base di Node.js, che porta JavaScript fuori dal browser, sui server.

Dove si scrive il codice

Ci sono tre posti, come per il CSS.

in linea

Dentro un attributo di evento, come onclick. Comodo per una prova, ma mescola contenuto e comportamento: da evitare.

<script> nella pagina

Il codice sta tra <script> e </script>. Va bene per pochi comandi legati a quella pagina.

<script src>

Il codice sta in un file .js esterno, condiviso da più pagine e memorizzato nella cache: la scelta normale.

Un <script> normale blocca la lettura della pagina finché non è stato scaricato ed eseguito; per questo un tempo si metteva in fondo al body. Oggi si mette nel head con l'attributo defer: il file si scarica in parallelo e viene eseguito quando l'HTML è completo, nell'ordine in cui compaiono gli script. L'elemento <noscript> mostra il suo contenuto solo se JavaScript è disattivato.

Come vedere i risultati

  • console.log(…) scrive nella console degli strumenti per sviluppatori. È lo strumento di lavoro quotidiano: accetta più valori separati da virgole e mostra anche oggetti e array. Esistono anche console.warn, console.error e console.table.
  • alert, confirm e prompt aprono finestre di dialogo che bloccano la pagina finché l'utente non risponde. Utili per esperimenti, quasi mai in un sito vero.
  • document.write scrive HTML nel punto in cui si trova lo script. È un residuo del passato: se chiamato dopo il caricamento cancella l'intera pagina. Non usarlo.
  • Il modo giusto per mostrare qualcosa all'utente è modificare il DOM, cioè la pagina: lo vedremo nel prossimo modulo.

Variabili e tipi

let, const e var

Una variabile si dichiara con una parola chiave:

  • const per un valore che non verrà riassegnato. È la scelta predefinita;
  • let per un valore che cambierà, come un contatore;
  • var è il modo antico, prima del 2015. Lo incontrerai nel codice vecchio, ma ha regole insidiose: vale per tutta la funzione invece che per il blocco tra graffe e si può ridichiarare senza errori.

I nomi distinguono maiuscole e minuscole (totale e Totale sono due variabili diverse), non possono iniziare con una cifra e per convenzione si scrivono in camelCase: prezzoTotale, numeroStudenti.

La differenza conta davvero nei cicli. Ogni giro di un for con let ha la sua copia della variabile; con var ce n'è una sola, condivisa, e quando le funzioni ritardate vengono eseguite il ciclo è già finito:

Variabili mai dichiarate. Assegnare un valore a un nome mai dichiarato (totale = 5) crea in silenzio una variabile globale, visibile ovunque: una fonte inesauribile di errori. Scrivendo 'use strict'; in cima al file, quell'assegnazione diventa un errore. Il modo rigoroso è già attivo nelle classi e nei moduli.

Tipi primitivi e oggetti

JavaScript è un linguaggio a tipizzazione dinamica: non si dichiara il tipo di una variabile, e la stessa variabile può contenere prima un numero e poi una stringa. I valori però un tipo ce l'hanno, e l'operatore typeof lo dice.

TipoEsempiNote
number42, 3.14, -0.5, NaN, Infinityun solo tipo per interi e decimali; NaN significa «non è un numero»
string'ciao', "ciao", `ciao`apici singoli, doppi o inversi, equivalenti tranne che per i template
booleantrue, false
undefinedundefinedil valore di una variabile dichiarata ma mai assegnata
nullnull«nessun valore», assegnato di proposito
bigint9007199254740993ninteri grandi a piacere
symbolSymbol('id')identificatori unici, uso avanzato
object{ nome: 'Anna' }, [1, 2], new Date()tutto ciò che non è primitivo, funzioni comprese

La differenza fondamentale: i primitivi si copiano per valore, gli oggetti per riferimento. Assegnare un oggetto a un'altra variabile non lo duplica: entrambe le variabili puntano allo stesso oggetto in memoria.

Primitivi: per valore 5 6 ab let a = 5; let b = a; b++; b è una copia: a resta 5 Oggetti: per riferimento x y { voto: 30 } const x = { voto: 28 }; const y = x; y.voto = 30; un solo oggetto: anche x.voto vale 30
Una variabile che contiene un oggetto ne contiene in realtà l'indirizzo.

Conversioni e confronti

Quando un operatore riceve tipi diversi, JavaScript converte da solo uno dei valori. La regola che sorprende di più riguarda il +: se uno dei due operandi è una stringa, concatena; gli altri operatori aritmetici invece convertono in numero.

Ci sono due operatori di uguaglianza. == (uguaglianza debole) converte i valori prima di confrontarli, con regole difficili da ricordare. === (uguaglianza stretta) non converte niente: due valori sono uguali solo se hanno stesso tipo e stesso valore. Lo stesso vale per != e !==.

Vero e falso: truthy e falsy

Nelle condizioni qualsiasi valore viene convertito in booleano. Sono falsy, cioè valgono come false, solo questi: false, 0, -0, 0n, '' (stringa vuota), null, undefined e NaN. Tutto il resto è truthy, anche '0', 'false', un array vuoto [] e un oggetto vuoto {}.

Ne derivano due scorciatoie per i valori predefiniti: a || b restituisce b se a è falsy, mentre a ?? b (nullish coalescing) lo fa solo se a è null o undefined. La differenza si vede con lo zero:

Controllo del flusso

if, switch e operatore ternario

La sintassi è quella del C e di Java. L'operatore ternario condizione ? se_vera : se_falsa è un if compatto che restituisce un valore. Lo switch confronta con === e, senza break, prosegue nei case successivi: si usa per raggruppare più casi.

I cicli

Oltre ai classici for, while e do … while (che esegue il corpo almeno una volta), JavaScript ha due cicli per scorrere le collezioni:

  • for (const x of collezione) scorre i valori di array, stringhe, Map, Set, liste di elementi della pagina;
  • for (const chiave in oggetto) scorre i nomi delle proprietà di un oggetto. Non usarlo sugli array: dà gli indici come stringhe.

Errori ed eccezioni

Un errore durante l'esecuzione lancia un'eccezione: lo script si interrompe, a meno che il codice non stia dentro un blocco try. Il blocco catch riceve l'oggetto errore; finally viene eseguito in ogni caso. Con throw si lancia un'eccezione propria.

I tipi di errore più frequenti: ReferenceError (nome inesistente), TypeError (operazione sul tipo sbagliato, come chiamare undefined o leggere una proprietà di null), SyntaxError (codice scritto male, che impedisce l'esecuzione dell'intero script) e RangeError (valore fuori dall'intervallo ammesso).

Funzioni

Tre modi di scriverle

FormaEsempioCaratteristiche
dichiarazionefunction area(b, h) { return b * h; }si può chiamare anche prima del punto in cui è scritta (hoisting)
espressioneconst area = function (b, h) { return b * h; };una funzione è un valore e si può assegnare a una variabile
frecciaconst area = (b, h) => b * h;sintassi breve; con un'espressione sola il return è implicito; non ha un suo this

Parametri: predefiniti, rest e spread

JavaScript non controlla il numero degli argomenti: quelli mancanti valgono undefined, quelli in più vengono ignorati. Si possono dare valori predefiniti ai parametri, e raccogliere un numero variabile di argomenti con il parametro rest ...nome, che diventa un array. Lo stesso simbolo ... usato in una chiamata fa il contrario: spread, cioè «spacchetta» un array in argomenti separati.

Funzioni come valori: le callback

Poiché le funzioni sono valori, si possono passare come argomenti ad altre funzioni. Una funzione passata per essere chiamata più tardi si chiama callback. È il meccanismo su cui si regge JavaScript nel browser: «quando l'utente clicca, chiama questa funzione», «quando arrivano i dati, chiama quest'altra».

Scope e closure

Lo scope (ambito) di una variabile è la zona di codice in cui è visibile. In JavaScript ci sono quattro livelli: globale (fuori da tutto), di modulo, di funzione e di blocco (tra graffe, per let e const). Una funzione vede le variabili dei blocchi che la contengono, non il contrario. Questo è lo scope lessicale: conta dove la funzione è scritta, non da dove viene chiamata.

Una funzione interna continua a vedere le variabili della funzione esterna anche dopo che questa è terminata. La combinazione di una funzione e delle variabili che si porta dietro si chiama closure. Serve, per esempio, a creare uno stato privato:

Hoisting in breve. Prima di eseguire un blocco, il motore registra le dichiarazioni. Le function sono disponibili da subito; le var esistono ma valgono undefined fino all'assegnazione; let e const esistono ma non si possono toccare prima della loro riga (zona morta temporale): usarle prima dà un ReferenceError.

Il valore di this

Dentro una funzione, this indica l'oggetto «su cui» la funzione è stata chiamata. Non dipende da dove la funzione è scritta, ma da come viene chiamata:

  • oggetto.metodo(): this è oggetto;
  • chiamata semplice funzione(): this è undefined in modo rigoroso (l'oggetto globale altrimenti);
  • con new: this è il nuovo oggetto creato;
  • in un gestore di eventi: l'elemento a cui è collegato;
  • le funzioni freccia non hanno un loro this: usano quello del codice che le circonda.

Oggetti e array

Oggetti letterali

Un oggetto è un insieme di coppie nome: valore, dette proprietà. Se il valore è una funzione la proprietà si chiama metodo. Si accede con il punto (studente.nome) o con le parentesi quadre (studente['nome']): le quadre servono quando il nome è in una variabile o contiene caratteri strani.

Destrutturazione e spread

La destrutturazione estrae in una sola riga i valori di un array o le proprietà di un oggetto e li mette in variabili. Lo spread ... fa il contrario: espande un array o un oggetto dentro un altro. È il modo comune di copiare e unire.

Gli array

Un array è una lista ordinata di valori, anche di tipi diversi, indicizzata da 0. La sua lunghezza è length e cresce da sola. I metodi principali:

MetodoChe cosa faModifica l'array?
push(x) / pop()aggiunge / toglie in fondosì
unshift(x) / shift()aggiunge / toglie all'iniziosì
splice(i, n, …nuovi)toglie n elementi dalla posizione i ed eventualmente ne inserisce altrisì
reverse(), sort()inverte, ordinasì
slice(i, j)copia gli elementi da i a j esclusono
concat(altro)restituisce l'unioneno
join(sep)unisce gli elementi in una stringano
indexOf(x), includes(x)posizione (o -1), presenzano

Il metodo sort senza argomenti confronta gli elementi come stringhe, quindi 100 viene prima di 9. Per i numeri gli si passa una funzione di confronto (a, b) => … che restituisce un numero negativo se a va prima di b, positivo se va dopo, zero se sono equivalenti.

forEach, map, filter, find, reduce

Questi metodi ricevono una callback che viene chiamata su ogni elemento. Sostituiscono la maggior parte dei cicli e si possono concatenare.

forEach(f)

Esegue f su ogni elemento. Non restituisce niente.

map(f)

Restituisce un nuovo array con i risultati di f: stessa lunghezza, valori trasformati.

filter(f)

Restituisce un nuovo array con i soli elementi per cui f è vera.

find(f)

Restituisce il primo elemento per cui f è vera, o undefined.

some(f) / every(f)

Vero se almeno uno / tutti gli elementi soddisfano f.

reduce(f, iniziale)

«Riduce» l'array a un solo valore, accumulando: somme, conteggi, raggruppamenti.

JSON

JSON (JavaScript Object Notation) è un formato di testo per scambiare dati, nato dalla sintassi degli oggetti JavaScript e oggi usato da qualsiasi linguaggio. È il formato in cui i server rispondono alle richieste delle pagine. Rispetto a un oggetto letterale è più rigido: i nomi delle proprietà vanno tra virgolette doppie, le stringhe pure; non ammette funzioni, undefined, commenti, né virgole finali.

Oggetti predefiniti

Stringhe e template literal

Le stringhe sono immutabili: i loro metodi restituiscono sempre una stringa nuova. I template literal, tra apici inversi `, possono andare a capo e inserire espressioni con ${…}.

Number e Math

Date

Un oggetto Date rappresenta un istante. La trappola da ricordare: i mesi vanno da 0 (gennaio) a 11 (dicembre), mentre i giorni del mese partono da 1. Per scambiare date con un server si usa il formato ISO 2026-01-15T10:30:00.

Prototipi e classi

Funzioni costruttore e prototipi

Per creare tanti oggetti dello stesso tipo si usa una funzione costruttore, chiamata con new: crea un oggetto vuoto, lo passa come this e lo restituisce. Per convenzione il nome ha l'iniziale maiuscola.

I metodi non si mettono in ogni oggetto, ma una volta sola nel prototipo (Costruttore.prototype). Ogni oggetto ha un collegamento nascosto al suo prototipo: quando si cerca una proprietà che l'oggetto non ha, JavaScript la cerca nel prototipo, poi nel prototipo del prototipo, e così via. È la catena dei prototipi, il meccanismo con cui JavaScript realizza l'ereditarietà.

anna nome: 'Anna'matricola: 7 Studente.prototype saluta()constructor Object.prototype toString()hasOwnProperty() null anna.saluta() non è in anna: si trova un gradino più su. anna.toString() due gradini più su.
Ogni oggetto rimanda al suo prototipo; la ricerca di una proprietà risale la catena fino a null.

La sintassi class

Dal 2015 JavaScript ha le classi, con una sintassi familiare a chi conosce Java. Sotto il cofano sono ancora costruttori e prototipi, ma il codice è molto più leggibile. Le parti di una classe:

  • constructor: il costruttore, eseguito da new;
  • i metodi, scritti senza la parola function;
  • get e set: metodi che si usano come proprietà;
  • static: membri della classe, non dei singoli oggetti;
  • i campi che iniziano con # sono privati: inaccessibili fuori dalla classe;
  • extends per ereditare, super per chiamare costruttore e metodi della classe madre.

Moduli

import ed export

In un progetto vero il codice si divide in più file. Un modulo è un file JavaScript che decide che cosa rendere visibile agli altri con export e che cosa usare degli altri con import. Tutto il resto resta privato del modulo: niente più variabili globali che si pestano i piedi.

  • si carica con <script type="module" src="…">, che è automaticamente defer e in modo rigoroso;
  • le esportazioni con nome si importano con le graffe, eventualmente rinominandole con as; quella predefinita (export default, una per file) si importa senza graffe, con il nome che si vuole;
  • import * as nome raccoglie tutte le esportazioni in un oggetto;
  • i percorsi sono relativi e includono .js; per motivi di sicurezza i moduli funzionano solo se la pagina è servita da un server web (anche localhost), non aprendo il file con un doppio clic.

Verifica