JavaScript - linguaggio, DOM ed eventi
In questa pagina 12
JavaScript è il linguaggio di programmazione dei browser: nasce nel 1995 e il suo standard si chiama ECMAScript (Ecma-262, nuova edizione ogni anno). Con HTML e CSS forma la triade del lato client: HTML è la struttura (HTML5 - struttura del documento, elementi semantici e formUn documento HTML5 ha la forma doctype (), html con lang, head (meta charset UTF-8, viewport, title, link, script) e body. Il parser HTML5 non dà mai errore: corregge (aggiunge il tbody, chiude i p). Gli elementi semantici (header, nav, main, section, article, aside, footer, figure, time) descrivono il ruolo del contenuto e danno ai lettori di schermo i punti di riferimento; div e span sono neutri. Link: a href (assoluto, relativo, #frammento, mailto), rel e target; immagini con alt obbligatorio. Tabelle: table, caption, thead, tbody, th con scope, td, colspan e rowspan, solo per dati. Form: action, method (GET mette i campi nella query string, per letture idempotenti e ricercabili; POST li mette nel corpo, per modificare lo stato), enctype (application/x-www-form-urlencoded predefinito, multipart/form-data per i file); si invia solo ciò che ha name; label for collega etichetta e campo; tipi di input (text, email, number, date, time, radio, checkbox, hidden...); validazione nativa con required, minlength, maxlength, min, max, step, pattern e type, aggirabile e quindi da ripetere sul server; novalidate la spegne. Accessibilità: lang, alt, label, gerarchia dei titoli, navigazione da tastiera, ARIA solo quando l'HTML nativo non basta.HTML5 - struttura del documento, elementi semantici e form →), CSS l'aspetto (CSS3 - selettori, cascata, box model e layoutCSS descrive la presentazione: regole selettore { proprietà: valore }. Selettori: tipo, classe (.a), id (#a), attributo ([type="date"]), universale, combinatori (spazio discendente, > figlio, + fratello adiacente, ~ fratelli seguenti), pseudo-classi (:hover, :focus-visible, :nth-child, :not, :checked) e pseudo-elementi (::before, ::after). Cascata: tra più regole che toccano la stessa proprietà vince, nell'ordine, l'importanza (!important vince, e lo stile inline batte gli stili normali), poi la specificità (a,b,c) = (id, classi+attributi+pseudo-classi, tipi+pseudo-elementi) confrontata come numeri uno alla volta da sinistra, infine l'ordine di comparsa (l'ultima vince). Ereditarietà: color, font, line-height, text-align passano ai figli; margin, padding, border, background, width no; inherit, initial, unset la controllano. Box model: content, padding, border, margin; con content-box width è solo il contenuto, con border-box include padding e bordo; i margini verticali adiacenti collassano nel maggiore. display: block, inline, inline-block, none, flex, grid. position: static, relative, absolute (rispetto all'antenato posizionato), fixed, sticky. Flexbox è per una dimensione (justify-content, align-items, gap, flex-grow, flex-wrap), grid per due (grid-template-columns, fr, repeat, minmax, gap). Responsive: meta viewport, unità relative (rem, %, fr), media query @media (min-width), approccio mobile-first.CSS3 - selettori, cascata, box model e layout →), JavaScript il comportamento. Oggi gira anche sul server (Node.js), ma qui interessa nel browser, dove accede al documento tramite il DOM e comunica con il server (Architettura delle applicazioni web - browser, server web e livelliUn'applicazione web è distribuita su più livelli (tier): presentazione (browser: HTML, CSS, JavaScript), logica applicativa (server web e application server) e dati (DBMS). Il client invia richieste HTTP, il server risponde; HTTP è senza stato, quindi lo stato dell'utente viaggia in cookie e sessioni. Il web server serve file statici, l'application server (container, per esempio Tomcat per le servlet Java) esegue codice che genera risposte dinamiche; spesso il web server fa da reverse proxy davanti all'application server. Il browser trasforma i byte della risposta in una pagina: decodifica, tokenizzazione e costruzione del DOM, CSS che diventa CSSOM, render tree, layout (reflow), paint e composizione; un script senza defer o async blocca il parsing, il CSS blocca il rendering. Origine = schema + host + porta; la same-origin policy limita ciò che uno script può leggere da altre origini. Web 1.0: pagine generate dal server, ogni azione ricarica la pagina; Web 2.0: AJAX, contenuti degli utenti, servizi REST; Web 3.0: dati con significato esplicito (RDF, linked data).Architettura delle applicazioni web - browser, server web e livelli →). Nonostante il nome, non ha niente a che fare con Java: la sintassi è simile per le parentesi graffe, il modello è diverso (tipi dinamici, funzioni come valori, oggetti senza classi obbligatorie). Per un richiamo ai concetti comuni di programmazione a oggetti, si veda Classi ed ereditarietà in PythonAttributi di istanza e di classe, metodi di istanza, di classe e statici; confronto e ordinamento con eq e lt; proprietà; ereditarietà, super(), override e polimorfismo; classi astratte come interfacce; eccezioni personalizzate; overloading e shadowing in Python.Classi ed ereditarietà in Python → e Eccezioni in PythonEccezioni e traceback, eccezioni predefinite più comuni, try/except/else/finally, raise per segnalare errori, propagazione lungo le chiamate.Eccezioni in Python →.
Gli esempi usano i dati dell'applicazione di prenotazione delle aule:
const prenotazioni = [
{ id: 1, aula_id: 1, giorno: "2026-10-19", ora_inizio: "09:00", ora_fine: "11:00", studente: "Rossi" },
{ id: 2, aula_id: 1, giorno: "2026-10-19", ora_inizio: "14:00", ora_fine: "16:00", studente: "Bianchi" },
{ id: 3, aula_id: 2, giorno: "2026-10-20", ora_inizio: "10:00", ora_fine: "12:00", studente: "Verdi" },
{ id: 4, aula_id: 3, giorno: "2026-10-21", ora_inizio: "09:00", ora_fine: "13:00", studente: "Rossi" }
];Il codice si include in una pagina con <script src="app.js" defer></script>; per provare un frammento si usa la console degli strumenti per sviluppatori del browser (F12) o node.
Tipi e valori
JavaScript è a tipi dinamici: le variabili non hanno un tipo, i valori sì, e si convertono quando serve. I tipi sono sette primitivi (immutabili) più gli oggetti:
| tipo | esempi | note |
|---|---|---|
number |
42, 3.14, NaN, Infinity |
un solo tipo numerico, virgola mobile a 64 bit |
string |
"ciao", 'ciao', template literal fra virgolette inverse |
immutabili; nei template literal le espressioni si inseriscono con il segno del dollaro e le graffe (esempio nel blocco sotto) |
boolean |
true, false |
|
undefined |
undefined |
variabile dichiarata e non assegnata, proprietà assente |
null |
null |
"nessun valore" voluto |
bigint |
10n |
interi di precisione arbitraria |
symbol |
Symbol("x") |
identificatori unici (uso avanzato) |
object |
{}, [], funzioni, date |
riferimenti: due variabili possono puntare allo stesso oggetto |
typeof 42 // "number"
typeof "ciao" // "string"
typeof undefined // "undefined"
typeof null // "object" <- errore storico del linguaggio, mai corretto
typeof [] // "object" (per gli array: Array.isArray([]) è true)
typeof (() => 1) // "function"
0.1 + 0.2 // 0.30000000000000004 (virgola mobile, come in ogni linguaggio)
"5" + 3 // "53" il + con una stringa concatena
"5" - 3 // 2 gli altri operatori convertono in numeroUguaglianza. == converte i tipi prima di confrontare e dà risultati sorprendenti (0 == "" è vero, "" == "0" è falso, null == undefined è vero); === (uguaglianza stretta) non converte: 1 === "1" è falso. Regola: usare sempre === e !==. NaN non è uguale a niente, neppure a se stesso: si controlla con Number.isNaN(x).
Veri e falsi. In un if ogni valore è convertito in booleano. I valori falsy sono solo otto: false, 0, -0, 0n, "", null, undefined, NaN. Tutto il resto è truthy, anche "0", "false", [] e {}. Gli operatori || e && restituiscono uno dei due operandi: 0 || "x" dà "x". Per distinguere "assente" da "zero" si usano ?? (usa il secondo solo se il primo è null o undefined: 0 ?? "x" dà 0) e l'accesso opzionale ?. (p.aula?.nome dà undefined invece di un errore se p.aula non esiste).
Conversioni. Number("42") è 42, Number("12px") è NaN, parseInt("12px") è 12, parseFloat("3.5kg") è 3,5; String(x) e x.toString() fanno il contrario. I valori letti da un campo di un form sono sempre stringhe ("80"), anche per type="number": vanno convertiti.
Variabili: let, const, var
const MAX_ORE = 4; // non si può riassegnare
let contatore = 0; // si può riassegnare
contatore = contatore + 1;leteconsthanno visibilità di blocco ({ ... }) e non si possono usare prima della dichiarazione (la zona morta temporale: dàReferenceError). Si usaconstper default,letquando serve riassegnare.var(vecchio) ha visibilità di funzione e viene sollevato (hoisting): la dichiarazione vale per tutta la funzione, ma il valore arriva solo all'assegnazione (typeof xprima divar x = 5dà"undefined"). Dentro un blocco{ var v = 1; },vresta visibile fuori. Non si usa più.constblocca il nome, non il contenuto:const p = { id: 1 }; p.id = 2;è lecito. Riassegnarep = {}dàTypeError.
Funzioni
function somma(a, b) { return a + b; } // dichiarazione: sollevata, usabile prima di essere scritta
const per = function (a, b) { return a * b; }; // espressione: la variabile vale solo dopo l'assegnazione
const quadrato = x => x * x; // arrow function: un parametro, corpo = espressione
const durata = (inizio, fine) => { // arrow function: corpo con return esplicito
const [hi, mi] = inizio.split(":").map(Number);
const [hf, mf] = fine.split(":").map(Number);
return (hf * 60 + mf) - (hi * 60 + mi);
};
durata("09:00", "11:30") // 150- Le funzioni sono valori: si assegnano a variabili, si passano come argomenti (callback), si restituiscono. È l'idea alla base di eventi e array.
durata:"09:00".split(":")dà["09","00"],.map(Number)converte in[9, 0], il destructuringconst [hi, mi] = ...assegna le due posizioni. Il risultato sono i minuti.- Parametri predefiniti, rest e template literal (esempio sotto):
nome = "ospite"vale se l'argomento manca;...nraccoglie gli argomenti in un array;Math.max(...[3, 9, 4])fa il contrario (spread: 9); nelle virgolette inverse il segno del dollaro seguito da graffe inserisce il valore di un'espressione.
function saluta(nome = "ospite") { return `Ciao ${nome}`; }
saluta() // "Ciao ospite"
saluta("Rossi") // "Ciao Rossi"
const somma2 = (...n) => n.reduce((a, b) => a + b, 0);
somma2(1, 2, 3, 4) // 10- Passare meno argomenti del previsto non è un errore: i mancanti sono
undefined.
Oggetti e array
Un oggetto è una raccolta di coppie chiave-valore; un array un oggetto con chiavi numeriche e metodi in più. Le prenotazioni qui sopra sono un array di oggetti, la stessa forma del JSON che arriva dal server (Web service, XML, JSON, SOAP e RESTUn web service e' un servizio software accessibile via rete da altri programmi, con messaggi in formato standard su HTTP; i formati di dati sono XML (marcatori annidati, attributi, namespace, validazione con XSD) e JSON (RFC 8259: oggetti, array, stringhe, numeri, true, false, null; piu' compatto e diretto per i linguaggi di programmazione); SOAP e' un protocollo di messaggi XML (Envelope con Header facoltativo e Body, Fault per gli errori) inviati di solito con una POST HTTP e descritti da un file WSDL; REST e' uno stile architetturale (Fielding) in cui il servizio espone risorse identificate da URI e le manipola con i metodi HTTP: GET legge, POST crea, PUT sostituisce, PATCH modifica, DELETE elimina, con codici di stato significativi (200, 201 con Location, 204, 400, 404, 409), senza stato sul server, con cache e interfaccia uniforme.Web service, XML, JSON, SOAP e REST →).
const p = prenotazioni[0];
p.studente // "Rossi" notazione col punto
p["ora_inizio"] // "09:00" notazione con le parentesi: la chiave può essere una variabile
const { studente, giorno } = p; // destructuring: due variabili
const copia = { ...p, studente: "Neri" }; // copia superficiale con un campo modificato
Object.entries({ a: 1, b: 2 }) // [["a", 1], ["b", 2]]
p === { ...p } // false: sono due oggetti diversi (si confrontano i riferimenti)I metodi degli array che non modificano l'originale e restituiscono un risultato sono il modo normale di elaborare i dati:
prenotazioni.filter(p => p.studente === "Rossi").map(p => p.id) // [1, 4]
prenotazioni.find(p => p.id === 3).studente // "Verdi" (find dà undefined se non trova)
prenotazioni.map(p => durata(p.ora_inizio, p.ora_fine)) // [120, 120, 120, 240]
prenotazioni.reduce((tot, p) => tot + durata(p.ora_inizio, p.ora_fine), 0) // 600 minuti in totale
prenotazioni.some(p => p.aula_id === 3) // true
prenotazioni.every(p => p.giorno === "2026-10-19") // falsefiltertiene gli elementi per cui la funzione è vera;maptrasforma ciascun elemento;reduceaccumula (qui parte da 0 e somma le durate);find,some,every,includes,forEach.sortmodifica l'array e senza comparatore ordina come stringhe:[10, 9, 1].sort()dà[1, 10, 9]. Per i numeri:[10, 9, 1].sort((a, b) => a - b)dà[1, 9, 10]; per le stringhea.localeCompare(b). Per non toccare l'originale:[...prenotazioni].sort(...).- Un conteggio per giorno senza librerie:
const conta = {};
for (const p of prenotazioni) conta[p.giorno] = (conta[p.giorno] ?? 0) + 1;
// { "2026-10-19": 2, "2026-10-20": 1, "2026-10-21": 1 }- JSON.
JSON.stringify(oggetto)produce il testo;JSON.parse(testo)lo rilegge (dàSyntaxErrorse non è JSON valido: le virgolette devono essere doppie). Le proprietà con valoreundefinede le funzioni vengono scartate.
JSON.stringify(prenotazioni[0])
// '{"id":1,"aula_id":1,"giorno":"2026-10-19","ora_inizio":"09:00","ora_fine":"11:00","studente":"Rossi"}'Classi. Sono zucchero sintattico su oggetti e prototipi (per chi viene da Java, vedere sotto):
class Prenotazione {
constructor({ id, aula_id, giorno, ora_inizio, ora_fine, studente }) {
Object.assign(this, { id, aula_id, giorno, ora_inizio, ora_fine, studente });
}
get minuti() { return durata(this.ora_inizio, this.ora_fine); }
toString() { return `${this.studente} ${this.ora_inizio}-${this.ora_fine}`; }
}
const pr = new Prenotazione(prenotazioni[3]);
pr.minuti // 240
String(pr) // "Rossi 09:00-13:00"Come la classe Java Prenotazione della parte lato server, ha costruttore, proprietà e metodi; non ha modificatori di accesso obbligatori (per i campi privati si usa #nome) né tipi dichiarati. Per i dati che arrivano dal server di solito bastano gli oggetti semplici.
this e arrow function
Dentro una funzione normale this dipende da come la funzione è chiamata: obj.metodo() dà this === obj; la stessa funzione staccata (const f = obj.metodo; f()) ha this indefinito (in modalità strict) o globale. Le arrow function non hanno un loro this: usano quello del punto in cui sono scritte (lessicale). Per questo nei callback dentro un metodo si usano le arrow function.
Closure
Una closure è una funzione che si porta dietro le variabili dell'ambiente in cui è stata creata, anche dopo che quell'ambiente è terminato.
function creaContatore() {
let n = 0;
return () => ++n; // la funzione restituita "ricorda" n
}
const c1 = creaContatore(), c2 = creaContatore();
c1(); c1(); c1(); // 1, 2, 3
c2(); // 1: ogni chiamata a creaContatore ha il proprio nOgni chiamata di creaContatore crea un nuovo n, visibile solo dalla funzione restituita (variabile "privata"). Usi tipici: funzioni configurate (cercaPer("aula_id")(1) restituisce le prenotazioni dell'aula 1) e callback degli eventi che ricordano il contesto. Il caso classico di errore con var:
for (var i = 0; i < 3; i++) setTimeout(() => console.log(i), 0); // stampa 3, 3, 3
for (let j = 0; j < 3; j++) setTimeout(() => console.log(j), 0); // stampa 0, 1, 2Con var c'è una sola i per tutto il ciclo e, quando i callback partono, vale già 3; con let ogni iterazione ha la sua copia.
Il DOM
Il DOM (Document Object Model, DOM Standard del WHATWG) è l'albero in memoria che il browser costruisce dall'HTML (Architettura delle applicazioni web - browser, server web e livelliUn'applicazione web è distribuita su più livelli (tier): presentazione (browser: HTML, CSS, JavaScript), logica applicativa (server web e application server) e dati (DBMS). Il client invia richieste HTTP, il server risponde; HTTP è senza stato, quindi lo stato dell'utente viaggia in cookie e sessioni. Il web server serve file statici, l'application server (container, per esempio Tomcat per le servlet Java) esegue codice che genera risposte dinamiche; spesso il web server fa da reverse proxy davanti all'application server. Il browser trasforma i byte della risposta in una pagina: decodifica, tokenizzazione e costruzione del DOM, CSS che diventa CSSOM, render tree, layout (reflow), paint e composizione; un script senza defer o async blocca il parsing, il CSS blocca il rendering. Origine = schema + host + porta; la same-origin policy limita ciò che uno script può leggere da altre origini. Web 1.0: pagine generate dal server, ogni azione ricarica la pagina; Web 2.0: AJAX, contenuti degli utenti, servizi REST; Web 3.0: dati con significato esplicito (RDF, linked data).Architettura delle applicazioni web - browser, server web e livelli →): ogni tag è un oggetto elemento, il testo è un nodo testo. Il punto d'ingresso è l'oggetto globale document. JavaScript legge e modifica l'albero, e il browser ridisegna.
Trovare elementi
document.getElementById("tabella") // per id (o null)
document.querySelector("tbody tr") // il primo che soddisfa un selettore CSS (o null)
document.querySelectorAll(".elimina") // tutti, in una lista statica
elemento.closest("tr") // l'antenato più vicino che soddisfa il selettore
elemento.parentElement, elemento.children // navigare nell'alberoI selettori sono quelli di CSS (CSS3 - selettori, cascata, box model e layoutCSS descrive la presentazione: regole selettore { proprietà: valore }. Selettori: tipo, classe (.a), id (#a), attributo ([type="date"]), universale, combinatori (spazio discendente, > figlio, + fratello adiacente, ~ fratelli seguenti), pseudo-classi (:hover, :focus-visible, :nth-child, :not, :checked) e pseudo-elementi (::before, ::after). Cascata: tra più regole che toccano la stessa proprietà vince, nell'ordine, l'importanza (!important vince, e lo stile inline batte gli stili normali), poi la specificità (a,b,c) = (id, classi+attributi+pseudo-classi, tipi+pseudo-elementi) confrontata come numeri uno alla volta da sinistra, infine l'ordine di comparsa (l'ultima vince). Ereditarietà: color, font, line-height, text-align passano ai figli; margin, padding, border, background, width no; inherit, initial, unset la controllano. Box model: content, padding, border, margin; con content-box width è solo il contenuto, con border-box include padding e bordo; i margini verticali adiacenti collassano nel maggiore. display: block, inline, inline-block, none, flex, grid. position: static, relative, absolute (rispetto all'antenato posizionato), fixed, sticky. Flexbox è per una dimensione (justify-content, align-items, gap, flex-grow, flex-wrap), grid per due (grid-template-columns, fr, repeat, minmax, gap). Responsive: meta viewport, unità relative (rem, %, fr), media query @media (min-width), approccio mobile-first.CSS3 - selettori, cascata, box model e layout →). querySelectorAll restituisce una fotografia, che non cambia se poi si aggiungono elementi; getElementsByTagName una lista "viva" (provato in un browser: 2 li prima di aggiungerne uno, getElementsByTagName ne vede 3, la lista statica 2).
Creare e modificare
const tr = document.createElement("tr"); // crea un elemento (non ancora nella pagina)
const td = document.createElement("td");
td.textContent = "Rossi"; // testo, non HTML
tr.append(td); // aggiunge come ultimo figlio
document.getElementById("tbody").append(tr); // ora compare
tr.dataset.id = "1"; // attributo data-id="1"
tr.classList.add("evidenza"); // anche remove, toggle, contains
tr.setAttribute("title", "Prenotazione 1"); // anche getAttribute, removeAttribute
tr.remove(); // toglie dall'albero
contenitore.replaceChildren(nuovoElemento); // sostituisce tutti i figlitextContentassegna testo: i caratteri<e&sono mostrati così come sono.innerHTMLassegna HTML, che il browser interpreta: se la stringa contiene dati dell'utente (un cognome scritto da qualcuno) si apre una vulnerabilità di cross-site scripting (XSS). Provato: impostando<img src=x onerror="...">,textContentlascia 0 elementi figli e mostra il testo;innerHTMLcrea un<img>vero, il cuionerroresegue codice. Regola: dati esterni sempre contextContent(ocreateElement);innerHTMLsolo per HTML scritto da noi.- Un elemento creato con
createElementesiste solo in memoria finché non lo si inserisce conappend,prepend,before,after,replaceChildren. - Per i form:
form.elements.studente.valuelegge un campo pername;input.valueè sempre una stringa;checkbox.checkedè un booleano.
Eventi
Un evento è qualcosa che accade: un clic, un tasto, l'invio di un form, il caricamento. Si registra una funzione (gestore, handler, o listener) che il browser chiama quando l'evento si verifica:
const pulsante = document.querySelector("button[type=submit]");
pulsante.addEventListener("click", function (evento) {
console.log("cliccato", evento.type, evento.target);
});
form.addEventListener("submit", e => { e.preventDefault(); /* niente invio classico */ });
selAula.addEventListener("change", disegna); // si passa il nome, senza parentesiaddEventListener(tipo, funzione): si possono registrare più gestori per lo stesso evento. Si passa la funzione, non il risultato di una chiamata (disegna, nondisegna()).- Eventi comuni:
click,input(a ogni modifica del campo),change(alla conferma del cambiamento),submit,keydown,focus,blur,DOMContentLoaded(DOM pronto),load. - L'oggetto evento ha
type,target(l'elemento su cui è avvenuto),currentTarget(l'elemento a cui è attaccato il gestore),preventDefault()estopPropagation(). preventDefault()annulla l'azione predefinita del browser: l'invio del form, il salto del link. Senza di esso, unsubmitricarica la pagina.
Propagazione
L'evento non resta sull'elemento: percorre l'albero in tre fasi:
- cattura (capturing): dalla radice (
document) giù fino al padre del bersaglio; - bersaglio (target): l'elemento su cui è avvenuto;
- bolla (bubbling): dal bersaglio su, fino alla radice.
I gestori registrati normalmente rispondono nella fase di bolla; con un terzo argomento true (o { capture: true }) rispondono in quella di cattura. Con <div id="a"><ul id="b"><li id="c"><button id="d"> e un gestore di clic su ciascun elemento, più uno in cattura su a, un clic su d produce (provato in un browser):
cattura a > bolla d (target=d, current=d) > bolla c (target=d, current=c) > bolla b (target=d, current=b) > bolla a (target=d, current=a)target resta d per tutta la corsa, currentTarget cambia. stopPropagation() ferma la propagazione: se c lo chiama, b e a non ricevono più l'evento in bolla (la cattura di a era già avvenuta).
Delegazione
La bolla permette di mettere un solo gestore sul contenitore invece di uno per elemento. Utile soprattutto per elementi creati dopo:
document.getElementById("tbody").addEventListener("click", e => {
const bottone = e.target.closest("button.elimina"); // il clic è partito da un bottone di eliminazione?
if (!bottone) return; // no: ignora
const riga = bottone.closest("tr");
eliminaPrenotazione(Number(riga.dataset.id)); // l'id sta in data-id
riga.remove();
});closest serve perché e.target può essere un elemento dentro il pulsante (un'icona); le righe aggiunte in seguito funzionano senza registrare altri gestori (provato: si elimina anche una riga appena aggiunta).
Moduli e modalità strict
Moduli. Per dividere il codice in file si usano i moduli ES: ogni file dichiara con export ciò che offre e con import ciò che usa.
// aule.js
export const aule = [{ id: 1, nome: "Aula A1", posti: 80 }];
export default function saluta() { return "ciao"; }<script type="module">
import saluta, { aule } from "./aule.js";
console.log(saluta(), aule[0].nome); // ciao Aula A1
</script>Uno script type="module" ha un proprio ambito (le sue variabili non diventano globali), è differito come defer, è sempre in modalità strict e va servito via HTTP (non da file://).
Modalità strict ("use strict"; all'inizio di un file o di una funzione): trasforma alcuni errori silenziosi in eccezioni. Per esempio assegnare a una variabile mai dichiarata (variabileGlobale = 1) senza strict crea una variabile globale; con strict dà ReferenceError. Inoltre in una funzione chiamata da sola this vale undefined invece dell'oggetto globale. Nei moduli e nelle classi è automatica.
Event loop ed esecuzione asincrona
JavaScript nel browser esegue il codice in un solo thread: una cosa alla volta. Eppure la pagina può aspettare il server senza bloccarsi. Il meccanismo è l'event loop (ciclo degli eventi, WHATWG HTML):
- lo stack delle chiamate (call stack) contiene le funzioni in esecuzione;
- operazioni lente (rete, timer, input) sono affidate al browser (le Web API), che le esegue fuori dal thread;
- quando un'operazione finisce, il suo callback viene messo in una coda: la coda dei task (macrotask;
setTimeout, gli eventi, i completamenti di rete) oppure la coda dei microtask (le reazioni delle promise eawait,queueMicrotask); - l'event loop, a stack vuoto, prende un task, lo esegue fino in fondo, poi svuota tutti i microtask, poi (se serve) il browser ridisegna, poi il task successivo.
Due conseguenze: un callback non interrompe mai il codice in corso (non c'è concorrenza nella stessa pagina) e un ciclo lungo blocca tutto (anche i clic e il ridisegno) finché non finisce.
console.log("A");
setTimeout(() => console.log("B"), 0); // task: dopo tutto il resto
Promise.resolve().then(() => console.log("C")); // microtask: appena lo stack si svuota
console.log("D");
// stampa: A D C BA e D sono sincroni; lo stack si svuota, i microtask passano prima del task del timer: C, poi B. Anche con ritardo zero, setTimeout non esegue mai subito. Con async/await:
console.log(1);
(async () => { console.log(2); await null; console.log(3); })(); // 2 subito, poi la funzione si ferma
console.log(4);
// stampa: 1 2 4 3Il corpo di una async function gira in modo sincrono fino al primo await; il resto è un microtask.
Promise, async e await
Una promise rappresenta un valore che arriverà: pending (in attesa), poi fulfilled (con un valore) o rejected (con un errore). .then registra cosa fare, .catch gli errori. async/await è la sintassi che le fa sembrare codice sequenziale: await sospende la funzione async (non il thread) finché la promise non si risolve.
fetch e AJAX
AJAX (Asynchronous JavaScript and XML) è il nome della tecnica con cui una pagina già caricata chiede dati al server in background e aggiorna solo una parte del DOM, senza ricaricare. Oggi si fa con fetch, che restituisce una promise (ai tempi si usava XMLHttpRequest, da cui la "X": oggi il formato dei dati è quasi sempre JSON):
async function caricaPrenotazioni(giorno) {
const risposta = await fetch("/api/prenotazioni?giorno=" + encodeURIComponent(giorno));
if (!risposta.ok) throw new Error("HTTP " + risposta.status); // 404, 500...: fetch NON rifiuta da solo
return await risposta.json(); // legge il corpo e lo trasforma da JSON
}
async function prenota(nuova) {
const risposta = await fetch("/api/prenotazioni", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(nuova)
});
if (!risposta.ok) throw new Error("HTTP " + risposta.status);
return await risposta.json();
}
caricaPrenotazioni("2026-10-19")
.then(righe => console.log(righe.length + " prenotazioni")) // 2 prenotazioni
.catch(err => console.error(err.message));fetchproduce una richiesta HTTP: metodo, intestazioni e corpo si scelgono come con curl (Caching, autenticazione, tipi MIME e URI in HTTPLa cache HTTP riusa le risposte senza contattare il server finche' sono fresche (Cache-Control: max-age, Expires; in mancanza una durata euristica pari a circa il 10% del tempo trascorso da Last-Modified) e, quando sono scadute, le rivalida con una richiesta condizionale (If-None-Match con ETag, If-Modified-Since con Last-Modified) alla quale il server risponde 304 senza corpo; no-store vieta di memorizzare, no-cache obbliga a rivalidare, private esclude le cache condivise. L'autenticazione usa 401 con WWW-Authenticate e la risposta Authorization: Basic (base64 di utente:password, solo sopra TLS) o Digest (hash con nonce); 407 vale per i proxy. Content-Type porta il tipo MIME (tipo/sottotipo; parametri come charset e boundary), Accept e gli altri header Accept-* guidano la negoziazione. Un URI (RFC 3986) e' scheme://userinfo@host:porta/percorso?query#frammento, con percent-encoding %HH per i byte non ammessi e regole per risolvere i riferimenti relativi.Caching, autenticazione, tipi MIME e URI in HTTP →). Il server risponde in JSON (Web service, XML, JSON, SOAP e RESTUn web service e' un servizio software accessibile via rete da altri programmi, con messaggi in formato standard su HTTP; i formati di dati sono XML (marcatori annidati, attributi, namespace, validazione con XSD) e JSON (RFC 8259: oggetti, array, stringhe, numeri, true, false, null; piu' compatto e diretto per i linguaggi di programmazione); SOAP e' un protocollo di messaggi XML (Envelope con Header facoltativo e Body, Fault per gli errori) inviati di solito con una POST HTTP e descritti da un file WSDL; REST e' uno stile architetturale (Fielding) in cui il servizio espone risorse identificate da URI e le manipola con i metodi HTTP: GET legge, POST crea, PUT sostituisce, PATCH modifica, DELETE elimina, con codici di stato significativi (200, 201 con Location, 204, 400, 404, 409), senza stato sul server, con cache e interfaccia uniforme.Web service, XML, JSON, SOAP e REST →).- La promise di
fetchè rifiutata solo per errori di rete; per le risposte con stato 4xx e 5xx va controllatorisposta.ok. encodeURIComponentcodifica il valore da mettere nell'URI (percent-encoding).- Più richieste indipendenti si fanno in parallelo con
Promise.all, che aspetta tutte:const [aule, righe] = await Promise.all([caricaAule(), caricaPrenotazioni(g)]);(verificato con un server simulato: due attese da 100 ms in parallelo durano circa 110 ms, in sequenza circa 220). - Dentro
async, gli errori si gestiscono contry { ... } catch (e) { ... }. - La risposta di
fetcharriva dopo: il codice che segue la chiamata, se non c'èawait, gira prima. Il rendering si fa nel punto in cui i dati sono disponibili.
La pagina dell'applicazione unisce tutto: all'avvio carica aule e prenotazioni con fetch, costruisce la tabella con il DOM, aggiorna con un gestore change e input sul filtro, e invia le nuove prenotazioni con POST: Esercizio - Tabella delle prenotazioni costruita con il DOM e filtrata (applicazione web) e Esercizio - Form HTML di prenotazione con validazione nativa e in JavaScript (applicazione web).
Errori tipici
- Usare
==e restare sorpresi dalle conversioni. - Credere che
constrenda l'oggetto immutabile. - Usare
varin un ciclo con callback asincroni. - Chiamare
sort()sui numeri senza comparatore. - Leggere
input.valuee sommarlo come numero (è una stringa). - Scrivere
addEventListener("click", f())(chiamafsubito) invece dif. - Dimenticare
preventDefault()nel gestore disubmit: la pagina si ricarica. - Assegnare dati dell'utente a
innerHTML: XSS. - Credere che
fetchfallisca con un 404 (serverisposta.ok). - Dimenticare
awaite lavorare su una promise anziché sul suo valore. - Bloccare la pagina con un ciclo lungo nel thread principale.
- Mettere il gestore su elementi creati dopo la registrazione, invece di usare la delegazione.
Domande d'esame
- Qual è l'ordine di stampa di
console.log("A"); setTimeout(() => console.log("B"), 0); Promise.resolve().then(() => console.log("C")); console.log("D");e perché? A D C B. Il codice sincrono (A, D) gira per primo; poi, con lo stack vuoto, i microtask delle promise (C); infine i task come il timer (B). - Che cosa succede quando si clicca un pulsante dentro un
lidentro unul, se tutti e tre hanno un gestore diclick? Come si evita di registrare un gestore per ogni riga di una tabella? Cattura dall'alto, bersaglio, poi bolla dal pulsante allie all'ul;stopPropagationinterrompe. Delegazione: un solo gestore sul contenitore, cone.target.closest(...)per riconoscere il pulsante, anche per le righe create dopo. - Spiegare closure e dire cosa stampa
for (var i = 0; i < 3; i++) setTimeout(() => console.log(i), 0); spiegare differenza fratextContenteinnerHTMLe fra==e===. Una closure ricorda le variabili dell'ambiente di creazione; il ciclo stampa 3, 3, 3 (una solaiconvar; conlet0, 1, 2).textContentinserisce testo,innerHTMLinterpreta HTML (XSS).===non converte i tipi.
Versione ripasso
Tipi. Primitivi: number, string, boolean, undefined, null, bigint, symbol; il resto sono oggetti (array, funzioni). typeof null è "object" (errore storico). Usare ===, non ==. Falsy: false, 0, -0, 0n, "", null, undefined, NaN. ?? e ?. per i valori assenti. input.value è una stringa.
Variabili. let/const: blocco, zona morta; var: funzione, hoisting. const non rende immutabile l'oggetto.
Funzioni. Dichiarazione (hoisted), espressione, arrow (this lessicale), parametri predefiniti, ...rest/spread, destructuring. Sono valori: si passano come callback.
Array e oggetti. map, filter, reduce, find, some, every; sort modifica e ordina come stringhe ((a, b) => a - b). Spread per copiare. JSON.stringify e JSON.parse (virgolette doppie). Esempio: prenotazioni.filter(p => p.studente === "Rossi").map(p => p.id) dà [1, 4].
Closure. La funzione ricorda l'ambiente in cui è nata (creaContatore). Con var nel ciclo i callback vedono un solo i (3, 3, 3); con let 0, 1, 2.
DOM. document.getElementById, querySelector(All), closest; createElement, append, remove, replaceChildren, classList, dataset. textContent = testo sicuro; innerHTML interpreta HTML, XSS con dati esterni. querySelectorAll è statica.
Eventi. addEventListener("click", f) (la funzione, non f()). Fasi: cattura, target, bolla; target fisso, currentTarget cambia. preventDefault annulla il comportamento predefinito (submit, link); stopPropagation ferma la corsa. Delegazione: un gestore sul contenitore con e.target.closest("button.elimina").
Moduli e strict. <script type="module"> con import/export: ambito proprio, differito, strict, servito via HTTP. "use strict": variabile non dichiarata dà ReferenceError, this indefinito nelle funzioni.
Event loop. Un solo thread; stack, coda dei task (timer, eventi, rete), coda dei microtask (promise, await) svuotata dopo ogni task. Ordine: A D C B; 1 2 4 3 con async. Il codice lungo blocca la pagina.
AJAX. fetch(url) dà una promise; controllare risposta.ok (404 non rifiuta); await risposta.json(); POST con headers Content-Type: application/json e body: JSON.stringify(...); Promise.all per richieste parallele; encodeURIComponent.
Errori tipici
==,sort()sui numeri,varnei cicli asincroni.addEventListener("click", f()).- Dimenticare
preventDefault,await,risposta.ok. innerHTMLcon dati dell'utente.- Gestori su elementi creati dopo, senza delegazione.
Contesto: HTML5 - struttura del documento, elementi semantici e formUn documento HTML5 ha la forma doctype (), html con lang, head (meta charset UTF-8, viewport, title, link, script) e body. Il parser HTML5 non dà mai errore: corregge (aggiunge il tbody, chiude i p). Gli elementi semantici (header, nav, main, section, article, aside, footer, figure, time) descrivono il ruolo del contenuto e danno ai lettori di schermo i punti di riferimento; div e span sono neutri. Link: a href (assoluto, relativo, #frammento, mailto), rel e target; immagini con alt obbligatorio. Tabelle: table, caption, thead, tbody, th con scope, td, colspan e rowspan, solo per dati. Form: action, method (GET mette i campi nella query string, per letture idempotenti e ricercabili; POST li mette nel corpo, per modificare lo stato), enctype (application/x-www-form-urlencoded predefinito, multipart/form-data per i file); si invia solo ciò che ha name; label for collega etichetta e campo; tipi di input (text, email, number, date, time, radio, checkbox, hidden...); validazione nativa con required, minlength, maxlength, min, max, step, pattern e type, aggirabile e quindi da ripetere sul server; novalidate la spegne. Accessibilità: lang, alt, label, gerarchia dei titoli, navigazione da tastiera, ARIA solo quando l'HTML nativo non basta.HTML5 - struttura del documento, elementi semantici e form →, CSS3 - selettori, cascata, box model e layoutCSS descrive la presentazione: regole selettore { proprietà: valore }. Selettori: tipo, classe (.a), id (#a), attributo ([type="date"]), universale, combinatori (spazio discendente, > figlio, + fratello adiacente, ~ fratelli seguenti), pseudo-classi (:hover, :focus-visible, :nth-child, :not, :checked) e pseudo-elementi (::before, ::after). Cascata: tra più regole che toccano la stessa proprietà vince, nell'ordine, l'importanza (!important vince, e lo stile inline batte gli stili normali), poi la specificità (a,b,c) = (id, classi+attributi+pseudo-classi, tipi+pseudo-elementi) confrontata come numeri uno alla volta da sinistra, infine l'ordine di comparsa (l'ultima vince). Ereditarietà: color, font, line-height, text-align passano ai figli; margin, padding, border, background, width no; inherit, initial, unset la controllano. Box model: content, padding, border, margin; con content-box width è solo il contenuto, con border-box include padding e bordo; i margini verticali adiacenti collassano nel maggiore. display: block, inline, inline-block, none, flex, grid. position: static, relative, absolute (rispetto all'antenato posizionato), fixed, sticky. Flexbox è per una dimensione (justify-content, align-items, gap, flex-grow, flex-wrap), grid per due (grid-template-columns, fr, repeat, minmax, gap). Responsive: meta viewport, unità relative (rem, %, fr), media query @media (min-width), approccio mobile-first.CSS3 - selettori, cascata, box model e layout →, Web service, XML, JSON, SOAP e RESTUn web service e' un servizio software accessibile via rete da altri programmi, con messaggi in formato standard su HTTP; i formati di dati sono XML (marcatori annidati, attributi, namespace, validazione con XSD) e JSON (RFC 8259: oggetti, array, stringhe, numeri, true, false, null; piu' compatto e diretto per i linguaggi di programmazione); SOAP e' un protocollo di messaggi XML (Envelope con Header facoltativo e Body, Fault per gli errori) inviati di solito con una POST HTTP e descritti da un file WSDL; REST e' uno stile architetturale (Fielding) in cui il servizio espone risorse identificate da URI e le manipola con i metodi HTTP: GET legge, POST crea, PUT sostituisce, PATCH modifica, DELETE elimina, con codici di stato significativi (200, 201 con Location, 204, 400, 404, 409), senza stato sul server, con cache e interfaccia uniforme.Web service, XML, JSON, SOAP e REST →, Esercizio - Tabella delle prenotazioni costruita con il DOM e filtrata (applicazione web). Elaborare i dati.
prenotazioni.filter(p => p.studente === "Rossi").map(p => p.id) // [1, 4]
prenotazioni.reduce((tot, p) => tot + durata(p.ora_inizio, p.ora_fine), 0) // 600
[10, 9, 1].sort() // [1, 10, 9]: ordine alfabetico
[10, 9, 1].sort((a, b) => a - b) // [1, 9, 10]
JSON.stringify(prenotazioni[0]) // '{"id":1,"aula_id":1,"giorno":"2026-10-19",...}'durata("09:00", "11:30") dà 150: split(":"), map(Number), minuti = ore per 60 più minuti.
Closure e var.
function creaContatore() { let n = 0; return () => ++n; } // c1() 1, 2, 3; c2() riparte da 1
for (var i = 0; i < 3; i++) setTimeout(() => console.log(i), 0); // 3, 3, 3
for (let j = 0; j < 3; j++) setTimeout(() => console.log(j), 0); // 0, 1, 2Propagazione (provata). Clic su d dentro c, b, a, con un gestore in cattura su a:
cattura a > bolla d > bolla c > bolla b > bolla a (target resta d, currentTarget cambia)stopPropagation in c ferma b e a. Delegazione:
tbody.addEventListener("click", e => {
const b = e.target.closest("button.elimina");
if (!b) return;
b.closest("tr").remove();
});Funziona anche per le righe create dopo. textContent inserisce testo; innerHTML interpreta HTML (provato con un img e onerror).
Event loop.
console.log("A"); setTimeout(() => console.log("B"), 0);
Promise.resolve().then(() => console.log("C")); console.log("D"); // A D C BI microtask (promise, await) passano prima del task successivo (timer, eventi). Una funzione async gira fino al primo await; poi si ferma e il resto è un microtask (1 2 4 3).
AJAX con fetch.
async function caricaPrenotazioni(giorno) {
const risposta = await fetch("/api/prenotazioni?giorno=" + encodeURIComponent(giorno));
if (!risposta.ok) throw new Error("HTTP " + risposta.status);
return await risposta.json();
}POST con method, headers Content-Type: application/json, body: JSON.stringify(nuova). Promise.all per richieste indipendenti: due attese da 100 ms durano circa 110 ms in parallelo, 220 in sequenza.
Moduli. export const aule = [...] e import saluta, { aule } from "./aule.js" in uno type="module": ambito proprio, differito, strict.
Domande d'esame, tracce.
- Ordine di stampa di
A,B,C,D: A D C B (sincrono, microtask, task). - Tre fasi di propagazione e delegazione per le righe create dopo.
- Closure e ciclo con
var;textContentcontroinnerHTML;==contro===. Valori e conversioni da sapere.
| espressione | risultato |
|---|---|
typeof null, typeof [], typeof (() => 1) |
"object", "object", "function" |
"5" + 3, "5" - 3 |
"53", 2 |
1 == "1", 1 === "1", null == undefined |
true, false, true |
| `0 | |
Number("12px"), parseInt("12px") |
NaN, 12 |
0.1 + 0.2 |
0.30000000000000004 |
let e const hanno visibilità di blocco e zona morta; var di funzione e hoisting; const p = {...}; p.id = 2 è lecito, p = {} no. this dipende da come si chiama la funzione; l'arrow function usa quello lessicale.
Funzioni e classi in sintesi.
const durata = (inizio, fine) => {
const [hi, mi] = inizio.split(":").map(Number);
const [hf, mf] = fine.split(":").map(Number);
return (hf * 60 + mf) - (hi * 60 + mi);
};
class Prenotazione {
constructor(d) { Object.assign(this, d); }
get minuti() { return durata(this.ora_inizio, this.ora_fine); }
}API del DOM da ricordare.
- Cercare:
getElementById,querySelector,querySelectorAll(statica),closest. - Creare e inserire:
createElement,append,replaceChildren,remove. - Attributi:
classList.add,dataset.id,setAttribute. - Form:
form.elements.nome.value(sempre stringa),checkbox.checked,form.reportValidity().
Eventi. click, input, change, submit, keydown, DOMContentLoaded; l'oggetto evento ha target, currentTarget, preventDefault(), stopPropagation(). Si registra f, non f().
Strict e moduli. "use strict": una variabile non dichiarata dà ReferenceError invece di diventare globale; this è undefined nelle funzioni chiamate da sole. Un modulo ha ambito proprio ed è sempre strict.
Esercizi su questo argomento
- Esercizio - Form HTML di prenotazione con validazione nativa e in JavaScript (applicazione web)
- Esercizio - Pagina AJAX per creare e cancellare prenotazioni (applicazione web)
- Esercizio - Tabella delle prenotazioni costruita con il DOM e filtrata (applicazione web)
- Esercizio - XML ben formato e valido con una DTD per le prenotazioni (applicazione web)