Evocare il passaggio dal vecchio codice disordinato al nuovo standard cristallino.

Var, Let e Const in JavaScript: La Guida Definitiva a Scope e Hoisting (2026)

Ancora confuso su quando usare var, let o const? Smetti di tirare a indovinare. Scopri la guida definitiva 2026 su Scope, Hoisting e Temporal Dead Zone per scrivere JavaScript moderno, sicuro e privo di bug.

Se hai iniziato a programmare con JavaScript prima del 2015, il tuo vocabolario per le variabili si limitava a una sola parola: var. Tuttavia, padroneggiare la triade var, let e const è oggi la competenza fondamentale per ogni sviluppatore moderno.

L’introduzione di ES6 (ECMAScript 2015) non ha portato solo “nuova sintassi”, ma ha risolto problemi architetturali storici del linguaggio. Comprendere le differenze non è solo una questione di stile; è la base per scrivere codice pulito (Clean Code), sicuro e performante.

In questa guida completa, analizzeremo non solo il come, ma il perché tecnico dietro Scope, Hoisting e la gestione della memoria.

Tabella Riassuntiva Rapida: Le Differenze

Prima di scendere nei dettagli tecnici, ecco la mappa mentale fondamentale:

Caratteristicavar (Legacy)let (Moderno)const (Moderno)
ScopeFunction Scope 🏠Block Scope 📦Block Scope 📦
Riassegnabile?✅ Sì✅ Sì❌ No
HoistingSì (inizializzato undefined)Sì (in TDZ 💀)Sì (in TDZ 💀)
Global PollutionSì (va su window)NoNo

1. La Battaglia dello Scope: Dove vive la tua variabile?

Lo scope definisce l’area del codice in cui una variabile è “visibile”. Questa è la distinzione più critica e il motivo principale per cui var è stata quasi del tutto abbandonata.

1.1 var: Scope di Funzione (Il vecchio approccio)

Le variabili dichiarate con var ignorano i blocchi di codice come if o for. Esse “vedono” solo i confini della funzione in cui si trovano. Se non sono in una funzione, sono globali.

function usaVar() {
    if (true) {
        var messaggio = "Sono accessibile ovunque nella funzione!";
    }
    // Nessun errore: var scavalca il blocco if!
    console.log(messaggio); 
}

1.2 let e const: Scope di Blocco (Il recinto sicuro)

Con let e const, le variabili nascono e muoiono all’interno delle parentesi graffe {} in cui sono dichiarate. Questo comportamento (Block Scope) previene fughe di dati involontarie.

function usaLet() {
    if (true) {
        let segreto = "Non puoi leggermi fuori";
    }
    // ❌ Errore: segreto is not defined
    // console.log(segreto); 
}

1.3 Il Bug del Loop: Perché var ti tradisce nell’asincrono

Questa è la classica domanda da colloquio tecnico. La differenza di scope diventa critica quando usi callback asincrone (come setTimeout) dentro un ciclo.

Visualizzazione della memoria: confronto tra un singolo nodo sovrascritto (var - magenta) e una sequenza ordinata di nodi distinti (let - teal) in un ciclo for.
Loop e Memoria: Perché ‘let’ crea una nuova variabile ad ogni giro.

Il problema con var:
Poiché var non ha scope di blocco, la variabile i è condivisa tra tutte le iterazioni. Quando il timer scatta (dopo 1 secondo), il ciclo è già finito e tutte le callback leggono lo stesso valore finale.

// ❌ Esempio errato con VAR
for (var i = 0; i < 3; i++) {
    // 'i' è la stessa variabile per tutti!
    setTimeout(() => console.log("Var: " + i), 1000);
}
// Output disastroso: "Var: 3", "Var: 3", "Var: 3"

La soluzione con let:
Grazie allo scope di blocco, let crea una nuova associazione per la variabile in ogni singola iterazione. Ogni timer “ricorda” il valore esatto di quel giro.

// ✅ Esempio corretto con LET
for (let i = 0; i < 3; i++) {
    // Una nuova 'i' viene creata per ogni iterazione
    setTimeout(() => console.log("Let: " + i), 1000);
}
// Output corretto: "Let: 0", "Let: 1", "Let: 2"

2. Hoisting e Temporal Dead Zone (TDZ)

L’Hoisting (sollevamento) è il comportamento del motore JavaScript che “sposta” le dichiarazioni in cima al loro scope. Ma c’è una sfumatura vitale da comprendere.

2.1 Var: Hoisting con inizializzazione

Con var, la variabile viene sollevata e inizializzata subito a undefined. Questo permetteva codice disordinato e buggato:

console.log(auto); // undefined (Nessun errore, ma dato sporco)
var auto = "Fiat";

2.2 Let/Const: La Temporal Dead Zone

Molti pensano che let e const non subiscano hoisting. Falso. Vengono sollevate, ma non inizializzate.

Il periodo di tempo tra l’ingresso nello scope e la dichiarazione effettiva si chiama Temporal Dead Zone (TDZ). Se provi a toccare la variabile nella TDZ, JavaScript lancia un errore, proteggendoti.

Grafico Timeline astratto: una variabile sale dalla zona di errore 'Dead Zone' (glitch magenta) alla zona sicura 'Initialized' (luce teal).
Attenzione alla TDZ: Dove il codice “muore” se tocchi la variabile troppo presto.
{
  // 💀 INIZIO TDZ
  // console.log(piatto); // ReferenceError: Cannot access before initialization

  let piatto = "Pasta"; // 🏁 FINE TDZ - La variabile ora è sicura
  console.log(piatto); // "Pasta"
}

3. Mutabilità e Gestione della Memoria

Quando usare let e quando const? La risposta sta nella mutabilità.

3.1 Const non significa “Immutabile al 100%”

const crea un legame (binding) immutabile. Una volta assegnato un valore a una costante, non puoi riassegnarla.

const TASSA = 22;
// TASSA = 25; // TypeError: Assignment to constant variable.

3.2 Il trucco degli Oggetti (Reference vs Value)

Attenzione: const blocca l’assegnazione, ma non congela il valore se questo è un oggetto o un array. In termini di memoria: protegge l’indirizzo di casa, ma non ti impedisce di cambiare l’arredamento interno.

Stack vs Heap: const blocca il puntatore, non l’oggetto.
const utente = { nome: "Mario" };

// ❌ ERRORE: Non puoi cambiare il riferimento (l'indirizzo)
// utente = { nome: "Luigi" }; 

// ✅ OK: Puoi modificare il contenuto all'interno!
utente.nome = "Luigi"; 
console.log(utente.nome); // "Luigi"

4. Best Practices per il 2025

Come scrivere codice pulito oggi? Segui questa semplice gerarchia:

  1. Default: const. Usa sempre const come prima scelta. Rende il codice più leggibile perché comunica che quel valore non dovrebbe cambiare.
  2. Opzione B: let. Usa let solo se sai per certo che il valore dovrà cambiare (es. contatori di loop, accumulatori).
  3. Mai: var. Non c’è quasi nessun motivo valido per usare var nel codice moderno, a meno che tu non stia lavorando su codice legacy molto datato.

Conclusione

Passare da var a let/const è stato uno dei più grandi salti di qualità nella storia di JavaScript. Hai guadagnato scope prevedibili, sicurezza contro gli errori di digitazione (grazie alla TDZ) e una gestione più chiara della memoria.

Sei pronto per il prossimo step? Ora che sai come dichiarare le variabili, scopri come estrarne i dati in modo elegante con la nostra guida sulla Destrutturazione in JavaScript (Prossimamente) o approfondisci come organizzare il tuo codice con i Moduli JavaScript.