var, let, const: scope, hoisting e la trappola di const
Differenze pratiche e perché const non rende immutabile un oggetto
Tre istruzioni per dichiarare una variabile: var, let, const. Fanno la stessa cosa di base: creano un nome a cui associare un valore, ma si comportano in modo molto diverso su dove vivono e quando diventano utilizzabili.
Possiamo pensare a tre modi di prenotare un tavolo. var è come urlare il tuo nome in un ristorante enorme: si sente ovunque, anche fuori dalla sala che ti interessa. let e const sono una prenotazione con il nome scritto solo sul tavolo assegnato.
1. Scope: dove vive la variabile
var ha lo scope di funzione: ignora il blocco di codice indentificato dalle parentesi graffe di if e for, ed è visibile in tutta la funzione che la contiene (o, fuori da funzioni, è globale). let e const hanno lo scope di blocco: esistono solo dentro il blocco di codice identificato da { ... } in cui sono scritte.
if (true) {
var a = 1;
let b = 2;
}
console.log(a); // 1 (var è "scappata" dal blocco if)
console.log(b); // ReferenceError: b is not defined
Var è come un messaggio scritto sulla bacheca comune di un condominio: lo legge chiunque, in ogni appartamento. let e const sono come un post-it attaccato dentro una singola stanza: chi è fuori da quella stanza non può leggere il contenuto del post-it.
Fonte: MDN Web Docs: «let» (block-scoped) e «var» (function-scoped).
2. Hoisting: la variabile esiste prima della sua riga
hoisting è il comportamento per cui JavaScript "conosce già" una dichiarazione prima di eseguire la riga dove compare: è come se la spostasse in cima al suo scope. Tutte e tre le dichiarazioni sono soggette a hoisting, ma con un esito diverso quando le usi troppo presto:
varviene inizializzata subito conundefined: leggerla prima non dà errore, restituisce solo un valore vuoto.leteconstvengono viste ma non inizializzate: accedervi prima della riga di dichiarazione lancia un ReferenceError.
console.log(x); // undefined (var è già lì, ma vuota)
var x = 1;
console.log(y); // ReferenceError: Cannot access 'y' before initialization
let y = 2;
3. La temporal dead zone (TDZ)
Quel periodo «pericoloso» dall'inizio del blocco fino alla riga della dichiarazione, ha un nome ufficiale: temporal dead zone. let, const e le classi ci restano dentro finché l'esecuzione non raggiunge la loro dichiarazione; qualunque tentativo di leggerle prima genera un ReferenceError.
Come un pacco in consegna con tracking «in transito»: sai che esiste ed è in arrivo (è stato «visto»), ma se provi a ritirarlo prima che il corriere suoni il campanello, non c'è nulla da prendere, solo un avviso di errore.
Fonte: MDN Web Docs: «let»: definizione ufficiale di temporal dead zone (TDZ).
4. Perché const non rende immutabile un oggetto
Qui si annida l'equivoco più comune: const crea un riferimento di sola lettura a un valore, non significa che il valore stesso sia immutabile. Riassegnare la variabile è vietato; modificare il contenuto di un oggetto o array che quella variabile referenzia è perfettamente legale.
const persona = {
nome: "Ada",
};
persona.nome = "Grace"; // OK: sto modificando l'oggetto, non riassegnando
console.log(persona.nome); // "Grace"
persona = {
nome: "Altra",
}; // TypeError: Assignment to constant variable.
Se vuoi davvero un oggetto a prova di modifica, serve un passo in più: Object.freeze(persona): è superficiale, blocca solo il primo livello di proprietà, non gli oggetti annidati dentro.
In sintesi
| var | let | const | |
|---|---|---|---|
| Scope | Funzione | Blocco | Blocco |
| Hoisting | Sì, = undefined | Sì, in TDZ | Sì, in TDZ |
| Riassegnabile | Sì | Sì | No |
| Oggetto mutabile | Sì | Sì | Sì |
La pratica raccomandata da molte guide di stile, MDN inclusa: usa const per default; passa a let solo se devi riassegnare; evita var nel codice nuovo. E ricorda: const blocca l'etichetta, non il contenuto.
Commenti (0)
Registrati per commentare, fare domande e proporre l'argomento della prossima pillola (oppure accedi se hai già un account).
Nessun commento. Sii il primo a scrivere qualcosa.