Javascript nel browser
Nella programmazione Javascript su browser, un programma Javascript viene eseguito esclusivamente in un contesto di esecuzione che è dato dal browser e dalla pagina web che lo ha richiamato. Una volta che viene aperta la pagina web (tramite accesso alla URL della pagina), il browser carica la pagina html e se trova nella pagina degli script Javascript collegati, allora li carica e li esegue.
Gli script possono essere posizionati o dentro il tag <head> o dentro il tag <body>.
Ad esempio:
<!doctype html>
<html>
<head>
<title>My home page</title>
<script src="script1.js" />
</head>
<body>
<h1>My home page</h1>
<p>Hello, I am a student and this is my Home page.</p>
<script src="script2.js" />
</body>
</html>
Entrambi i modi sono validi, ma come vedremo tra poco c’è differenza tra questi due caricamenti.
Quando la pagina html viene caricata dal browser, questo la trasforma in una pagina web visualizzabile dall’utente, e contemporaneamente crea una rappresentazione Javascript della pagina, entità che si chiama DOM (Document Object Model) e che contiene la struttura della pagina HTML e di ogni tag al suo interno ed è quello che permette la connessione tra html e Javascript.
Tramite Javascript quindi possiamo accedere al DOM tramite l’oggetto document. Per poter accedere ai singoli elementi di pagina è necessario eseguire una operazione chiamata “binding” che associa un elemento di pagina HTML ad un oggetto Javascript, e tramite questo permette di leggere, modificare e gestire la pagina HTML.
Binding
L’oggetto document ha un metodo “getElementById” che permette di ricercare uno specifico tag tramite attributo “id“.
Ad esempio poniamo di aver definito in html un oggetto button:
<button id="button" type="button"></button>
si può eseguire il binding di questo oggetto con questa istruzione:
const button = document.getElementById("button");
A questo punto l’oggetto button diventa un oggetto Javascript, e si può accedere alle sue funzionalità. Naturalmente per poter funzionare questo meccanismo è necessario che i tag HTML abbiano ID univoci.
Lettura
const input = document.getElementById("input");
const value = input.value;
Come si può vedere, possiamo leggere il contenuto di un tag input, quindi un input dell’utente, e memorizzarlo in una variabile.
Scrittura
Grazie agli oggetti del DOM, è possibile modificare l’html.
const divResult = document.getElementById("result");
const value = "ciao";
divResult.innerText=value;
Questa azione compie una modifica immediata dell’html e quindi del testo visualizzato dall’utente. In questo esempio specifico il testo di “divResult” assume il valore di value, che va a sostituire quanto era presente in precedenza.
Eventi
Vediamo poi la proprietà onclick, che può essere assegnata ad una funzione.
button.onclick = () => {
console.log("button clicked");
}
Quando l’utente preme il pulsante denominato “button”, viene emesso un evento DOM che si chiama “click”. Quando viene emesso questo evento il runtime di Javascript va a vedere se è stata valorizzata la proprietà “onclick” di quell’oggetto con una funzione, chiamata handler.
Se esiste un handler per la proprietà onclick, allora viene eseguito.
Gli eventi che si possono ascoltare sono molti: il click del mouse, il passaggio del mouse, lo scroll, la pressione di un tasto, ed è quindi possibile eseguire una funzione per ciascuno di questi eventi.
Mettiamo insieme tutto quanto detto finora con un semplice programmino che legge un input, e valorizza un div alla pressione di un pulsante.
HTML:
<!DOCTYPE html>
<html>
<head></head>
<body>
<input id="input" type="text" />
<button id="button" type="button">
Invio
</button>
<div id="result" />
<script src="src/index.js"></script>
</body>
</html>
JS:
const button = document.getElementById("button");
const divResult = document.getElementById("result");
button.onclick = () => {
const input = document.getElementById("input");
const value = input.value;
divResult.innerText=value;
}
Evento load
Anche l’oggetto document ha i suoi eventi. Tra questi il più importante è l’evento load, che indica il completo caricamento del DOM nell’oggetto document, e che garantisce che tutti gli oggetti sono pronti per essere collegati a Javascript. Questo evento è necessario perchè la trasformazione dell’html in DOM (e quindi nell’oggetto document) richiede tempo.
Qui torniamo alla differenza tra mettere lo script JS in head oppure al termine del body.
Se lo mettiamo in head lo script Javascript viene caricato ed eseguito subito, PRIMA che venga caricato il DOM. Questo script quindi non sarà in grado di vedere la pagina HTML prima che venga emesso un evento document.load. Per risolvere quindi bisogna eseguire:
document.onload = () => {
... istruzioni sul DOM
}
Questa operazione non è necessaria se includiamo lo script al termine del body della pagina html, perché questo verrà caricato ed eseguito DOPO il caricamento del DOM.
Dall’HTML all’applicazione web
Anche senza Javascript è possibile interagire con la pagina web: ad esempio è possibile scrivere form, cliccare su link e pulsanti, ecc. ma tutte queste operazioni richiedono in qualche modo un ricaricamento ed una interazione con macchine che da remoto ci reinviano una nuova pagina html statica.
Grazie a Javascript, invece, la pagina web smette di essere statica, ed è possibile interagire con la pagina stessa senza doverla ricaricare (e come vedremo sarà anche possibile aggiornare le informazioni da remoto, sempre senza un ricaricamento).
Le pagine web dinamiche sono a tutti gli effetti chiamate applicazioni web, e sono composte da tre file distinti:
– un html, che va a costituire la pagina web e che contiene i contenuti della pagina e l’associazione agli altri due componenti;
– uno o più css, che contengono le regole di della pagina html a cui sono associati;
– uno o più script js, che contengono il codice che permette di animare la pagina, modificare l’html, reagire alle azioni dell’utente.
Mentre html e css rappresentano l’elemento visuale della web app, e sono componenti “passivi“, il programma Javascript è invece il componente “attivo“, in grado di controllare i contenuti della pagina html, gestire l’interazione con l’utente, interagire con l’esterno, salvare dati, eseguire calcoli ed algoritmi.
Essi funzionano insieme nel contesto applicativo determinato dal browser web, che mostra i contenuti HTML/CSS ed esegue il codice Javascript.
DOM e BOM
Ora che abbiamo una idea di come funziona una applicazione web, proviamo a vedere in generale il funzionamento generale della connessione tra Javascript, e browser.
Il codice Javascript interagisce con due soggetti: la pagina web ed il browser, tramite opportuni oggetti che forniscono una interfaccia di programmazione (detta anche API[1]) che gli consente di accedere sia alle risorse della pagina html, sia alle risorse della finestra del browser.
Il DOM è l’API di pagina mentre l’API che gestisce la finestra si chiama BOM (Browser Object Model). Il CSS resta invece indipendente dal Javascript ed agisce sull’HTML direttamente tramite browser.
Qui una schematizzazione di questo modello.

Oggetto document
Il DOM è rappresentato in Javascript con un oggetto globale document visibile in Javascript.
L’oggetto document rappresenta la pagina HTML: tramite questo oggetto è possibile accedere ad ogni singolo elemento di pagina, attraverso opportune funzioni che effettuano una interrogazione (query) sulla pagina.
E’ possibile eseguire query anche sul singolo elemento (es. un DIV) per ricercare oggetti contenuti in questo. Vediamo le principali query di pagina:
Funzione Query | Cosa fa |
document.getElementById(idValue) | richiede a document un oggetto di tipo Element che corrisponde ad un tag html con id idValue. Se non presente restituisce null. Se sono presenti più oggetti che rispondono a quell’id, l’oggetto selezionato è il primo individuato. |
document.getElementByTagName(idValue) | richiede a document un oggetto di tipo Element che corrisponde ad un tag html con tag idValue. Se non presente restituisce null. Se sono presenti più oggetti che rispondono a quell’id, l’oggetto selezionato è il primo individuato. |
document.getElementByClassName(idValue) | richiede a document un oggetto di tipo Element che corrisponde ad un tag html con classe idValue. Se non presente restituisce null. Se sono presenti più oggetti che rispondono a quell’id, l’oggetto selezionato è il primo individuato. |
document.querySelector(selettore) | richiede a document un oggetto di tipo Element che corrisponde al selettore CSS. Se non presente restituisce null. |
document.querySelectorAll(selettore) | richiede a document un aray oggetto di tipo Element che corrisponde al selettore CSS. |
Esempi:
Funzione Query | Esempio |
document.getElementById(idValue) | const button = document.getElementById("button") |
document.getElementByTagName(idValue) | const button = document.getElementByTag("a") |
document.getElementByClassName(idValue) | const button = document.getElementByClassName("container") |
document.querySelector(selettore) | document.querySelector("a") |
document.querySelectorAll(selettore) | document.querySelector("a") |
Le ultime due funzioni querySelector e querySelectorAll utilizzano i selettori CSS, cioè gli stessi degli stili.
In questa tabella i selettori più importanti:
Nome | azione | esempio |
.class | Identifica tutti gli oggetti con quel nome di classe | .container |
#id | Identifica tutti gli oggetti con un certo id | #input1 |
tag | Identifica tutti gli oggetti con quel tag | a |
tag[attributo] | Identifica tutti gli oggetti con quel tag e quell’attributo valorizzato | a[title] |
tag[attributo=valore] | Identifica tutti gli oggetti con quel tag e quell’attributo valorizzato con quel valore | input[type=text] |
I selettori sono applicabili anche insieme, come vedremo negli esempi qui sotto.
Query | Risultato |
const rowList = document.querySelectorAll(".row") | Seleziona tutti gli oggetti con classe “.row” e li mette in un array. |
const divRowList = document.querySelectorAll("div.row") | Seleziona tutti gli oggetti di tipo div con classe “.row” e li mette in un array. |
const primaLabel = document.querySelector("a") | Seleziona la prima ancora che trova nella pagina HTML |
const row = document.querySelectorAll("li")[1] | Seleziona il secondo li della lista. |
const li = document.querySelector("li[value]" | Seleziona il primo li che ha un attributo value valorizzato |
const li = document.querySelector("li[value=3]" | Seleziona il primo li che ha un attributo value = 3 |
I querySelector sono in generale più potenti ed efficaci rispetto ai metodi getElementBy in ogni caso il loro comportamento è identico: servono per cercare un oggetto (o più oggetti) in pagina.
Una volta acquisito l’elemento è possibile accedere alle sue proprietà ed i suoi metodi. Qui alcune proprietà importanti.
Proprietà | Cosa fa |
element.innerText | legge il contenuto testuale di un elemento |
element.innerHTML | legge il contenuto HTML di un elemento |
element.innerText = value; | Sostituisce il contenuto dell’elemento con il valore passato. Il testo viene inserito in pagina. |
element.innerHTML = htmlValue; | Sostituisce il contenuto del tag con il contenuto (che deve essere codice HTML valido). Il contenuto viene immediatamente inserito in pagina e considerato HTML. |
element.classList.add(class); | Aggiunge una classe CSS ad un elemento |
element.classList.remove(class); | Rimuove una classe CSS ad un elemento |
Esempi:
Proprietà | Esempio |
element.innerText | const text = divContent.innerText; |
element.innerHTML | const html = divContent.innerHTML; |
element.innerText = value; | divContent.innerText = "ciao"; |
element.innerHTML = htmlValue; | divContent.innerHTML = "<p>Ciao</p>" |
element.classList.add(class); | element.classList.add('visible'); |
element.classList.remove(class); | element.classList.remove('visible'); |
Tra le proprietà hanno fondamentale importanza le proprietà associate ad eventi. A queste proprietà non viene associato un valore, ma una funzione che sarà eseguita se accade l’evento associato. Questa funzione viene chiamata listener (o handler).
Vediamo come esempio l’evento click del mouse su un oggetto.
Eventi | Cosa fa | Esempio |
element.onclick = funzione; | Collega una funzione all’evento click su oggetto element (tipicamente si tratta di un button ma l’evento click avviene su qualsiasi oggetto). Ogni volta che viene emesso quell’evento la funzione viene eseguita. | button.onclick = (event) => { console.log("Button clicked!");} |
Elenco di eventi a cui è possibile aggiungere un listener:
Evento | Descrizione |
onclick | Click su un elemento (non necessariamente un bottone) |
ondblclick | Doppio click |
onfocus | l’utente ha cliccato sull’elemento (in genere di un form) per scriverci o modificarlo |
oninput | avviene quando l’utente scrive in un campo di input |
onkeydown | accade quando un utente preme un tasto sulla tastiera |
onscroll | accade quando avviene uno scroll |
onmouseover | Passaggio del mouse sopra l’elemento |
onmouseleave | Uscita del passaggio del mouse |
Esempio:
const input1 = document.querySelector("#input1");
const primaColonna1 = document.querySelector("#primaColonna1");
input1.onfocus = () => {
primaColonna1.innerText = "Focus su input 1";
}
In questo esempio, vediamo che JS intercetta l’evento focus (cioè quando l’utente seleziona un elemento, in questo caso un input text) e all’evento esegue la funzione, che nello specifico inserisce un testo in uno specifico div.
Oggetto window
Il BOM è il Browser Object Model. Identifica le azioni e gli oggetti legati alla finestra del browser. Il browser, una volta caricato il codice JS, crea un oggetto chiamato window. Mentre document rappresenta la pagina HTML, window rappresenta la finestra vera e propria del browser, e permette quindi di visualizzare e modificare le sue proprietà, ed accedere alle sue funzioni, compreso l’accesso ad internet e allo storage locale.
Qui un elenco di comandi base (notare che con window non è necessario premettere il nome dell’oggetto):
Funzionalità | Cosa fa |
console.log(message) | scrive un messaggio nella console. |
alert(message); | apre un popup di messaggio |
open(url, target); | apre una nuova url, nella stessa pagina o altra pagina. |
location.href = url; | modifica la url della pagina. |
setTimeout(funzione, x); | esegue una funzione dopo x millisecondi. |
setInterval(funzione, x); | esegue una funzione ogni x millisecondi. |
clearInterval(interval) | interrompe l’esecuzione periodica |
Esempi:
Funzionalità | Esempio |
console.log(message) | console.log("ciao"); |
alert(message); | alert('ciao'); |
open(url, target); | open('www.google.com'); |
location.href = url; | location.href = "www.google.com"; |
setTimeout(funzione, x); | setTimeout(() => { console.log("ciao"); }, 2000); |
setInterval(funzione, x); | const i = setInterval(() => { console.log("ciao"); }, 2000); |
clearInterval(interval) | clearInterval(i) ; |
Esempio:
setTimeout(() => {
alert("Ciao");
}, 3000);
Se inseriamo questo codice e ricarichiamo la pagina, il Javascript eseguirà alert con messaggio “Ciao” dopo 3 secondi dall’esecuzione del codice.
Web storage
Nel browser è possibile salvare qualsiasi stringa (non è obbligatorio ma si consiglia di usare il formato JSON) in una memoria permanente del browser collegata alla pagina web. Questi dati non sono cancellati quando ricarichiamo la pagina e quindi con il web storage possiamo salvare localmente i dati dell’applicazione senza perderli.
Esistono diversi tipi di storage.
Local storage
I dati sono salvati associandoli a delle chiavi. Ad esempio:
localStorage.setItem("cognome", "Bianchi");
salva la stringa “Bianchi” nella chiave “cognome”. Per ricaricarla si usa invece:
let value = localStorage.getItem("cognome");
che ricaverà il valore “Bianchi”.
Per cancellare tutte le chiavi si usa:
localStorage.clear();
Bisogna ricordarsi di ricaricare i dati ad ogni avvio della pagina (e dello script Javascript). Inoltre i dati al primo avvio non ci sono, quindi bisogna sempre verificare che siano presenti.
Session storage
Il “session storage” è Identico al local storage, in questo caso però le chiavi vengono cancellate alla chiusura della finestra del browser. Può essere utile in tutte quelle situazioni in cui ci serve che i dati siano mantenuti al ricaricamento della pagina, ma non alla chiusura dell’applicazione del browser.
Cookies
Local e session storage sono stati introdotti nei browser a partire dal 2015. Esiste un sistema più “antico” per salvare i dati, che pur essendo più complesso è ancora largamente utilizzato perché permette una funzionalità in più che vedremo quando introdurremo AJAX. Anche i cookie salvano i dati in locale in modo permanente.
Per creare un cookie (basico) è sufficiente eseguire la seguente istruzione:
document.cookie = "cognome=bianchi; ";
Oppure, per più cookies:
document.cookie = "cognome=bianchi;nome=mario";
e per rileggerlo è sufficiente:
let valueString = document.cookie;
Il valore letto è quindi una stringa di coppie nome=valore separate da punto e virgola. E’ compito del programmatore eseguire lo split (separatore “;”) e l’estrazione dei dati, ma come vedremo sotto c’è una libreria che ci può aiutare.
Il cookie, come il local storage, rimane salvato sia se si ricarica la pagina.
Se tuttavia si chiude il browser, verrà cancellato (si dice che è un “session cookie”).
E’ tuttavia possibile fissare una durata più lunga ad esempio con la direttiva max-age:
document.cookie = "chiave=valore; max-age=3600";
dove max-age è il numero di secondi (in questo caso 3600 cioè un’ora) in cui il cookie dovrà restare valido prima della sua cancellazione.
E’ disponibile anche una libreria che semplifica l’uso dei cookie: js-cookie, che si può importare in pagina da qui: https://cdn.jsdelivr.net/npm/js-cookie@3.0.5/dist/js.cookie.min.js
Il suo funzionamento rende i cookie molto simili al local storage:
Cookies.set('name', 'value');
Oppure
Cookies.set('name', 'value', { expires: xx };
dove xx è un numero di giorni.
Per caricare invece:
let value = Cookies.get('name');
(qui la doc ufficiale: https://www.jsdelivr.com/package/npm/js-cookie )
[1] una API è in generale una libreria scritta da terzi che contiene dei metodi pubblici che sono a disposizione del programmatore e che consentono di utilizzarla nella propria applicazione.
[2] Come si può vedere nel codice JS, usando il carattere “`” come delimitatore di stringhe si può scrivere una stringa su più righe: molto comodo per scrivere html in modo leggibile.
[3] Questo modello di programmazione è alla base di tutta la programmazione Javascript moderna, ed è utilizzata da tutti i principali framework Javascript (es. React o Angular). Non è l’unico sistema: il DOM permette si modificare l’html con metodi come appendChild o createElement, ma questo tipo di programmazione parte dalla concezione che l’html e i dati siano la stessa cosa. In questo corso invece la scelta progettuale è invece quella di tenere rigidamente separati la visualizzazione (html) dal codice (js), preferendo quindi manipolare il DOM passando direttamente dell’HTML al browser.