La parola chiave var in JavaScript
Scopri come funziona la vecchia parola chiave var in JavaScript: scope di funzione, hoisting, variabili globali accidentali, ridichiarazione e il classico bug di closure nei cicli.
In JavaScript, il modo in cui si creano e si utilizzano le variabili influisce direttamente sul comportamento del codice. La parola chiave var è stata usata per decenni per dichiarare variabili. Da quando ES6 ha introdotto let e const, var è raramente la scelta giusta nel codice moderno — ma la incontrerai ancora in tutorial, domande da colloquio e progetti legacy. Questo capitolo spiega esattamente come funziona var, perché le sue regole di scoping e hoisting sorprendono gli sviluppatori, e quando (se mai) dovresti usarla oggi.
Questa pagina tratta: come viene definito lo scope di var, l'hoisting e la trappola di undefined, le variabili globali accidentali, la ridichiarazione, il famoso bug di closure nei cicli e le alternative più sicure con let/const.
Introduzione alla dichiarazione di variabili con var
La parola chiave var dichiara una variabile, opzionalmente inizializzandola a un valore. Le variabili dichiarate con var hanno scope di funzione o scope globale (mai scope di blocco), e sono soggette all'hoisting, che può produrre comportamenti che sorprendono gli sviluppatori provenienti da altri linguaggi. Per le basi sulla dichiarazione delle variabili, consulta Variabili JavaScript.
Scope di funzione
Una variabile dichiarata con var all'interno di una funzione è locale a quella funzione e accessibile ovunque al suo interno. Cosa fondamentale: var non rispetta i limiti dei blocchi — anche quando dichiarata all'interno di un blocco come un'istruzione if o un ciclo for, la variabile "fuoriesce" ed è visibile in tutta la funzione che la contiene.
Questa è la differenza più grande rispetto a let e const: con queste, x esisterebbe solo all'interno del blocco if, e il console.log genererebbe un ReferenceError. Consulta Scope delle variabili per il quadro completo sullo scope di blocco.
Hoisting
L'hoisting è il comportamento di JavaScript che tratta le dichiarazioni come se fossero spostate all'inizio del loro scope di appartenenza. Per un var, viene issata solo la dichiarazione, non l'assegnazione — quindi il nome esiste dall'inizio della funzione ma contiene undefined fino a quando l'esecuzione raggiunge la riga che lo assegna.
Leggere y prima della sua riga var restituisce undefined invece di un ReferenceError. Questo è ciò che rende l'hoisting di var subdolo: il codice sembra "funzionare", ma un errore di battitura o un'assegnazione mal posizionata può leggere silenziosamente undefined.
Anche let e const vengono issati, ma vivono nella temporal dead zone fino all'esecuzione della loro dichiarazione, quindi leggerli prima genera un errore invece di restituire silenziosamente undefined — di solito è quello che si vuole davvero:
Variabili globali e la parola chiave var
Quando var viene usata al di fuori di qualsiasi funzione, diventa una variabile globale accessibile da qualsiasi punto. Nei browser, questo la associa anche come proprietà dell'oggetto globale (window), cosa che let e const non fanno. Il rischio: due script che dichiarano entrambi var config si sovrascriveranno silenziosamente a vicenda.
var globalVar = "I am global";
// In a browser: window.globalVar === "I am global" → true
let blockGlobal = "scoped";
// window.blockGlobal → undefined (let/const do not become window properties)Dimenticarsi di dichiarare una variabile del tutto (assegnando a un nome non dichiarato in modalità non-strict) crea anch'esso un globale accidentale — un altro motivo per usare "use strict" e preferire let/const.
Limitazioni di var e alternative moderne
Sebbene var sia stata una parte fondamentale di JavaScript, presenta limitazioni che hanno portato all'introduzione di let e const in ES6 (ECMAScript 2015), che offrono dichiarazioni di variabili con scope di blocco.
Confusione tra hoisting e scope
Il comportamento dell'hoisting e la natura con scope di funzione di var possono creare confusione, in particolare nei costrutti di ciclo o nei blocchi condizionali, dove ci si aspetta intuitivamente variabili con scope di blocco.
Ridichiarazione di var e anomalie di closure nei cicli
- Ridichiarazione: a differenza di
leteconst,varpermette di ridichiarare la stessa variabile nello stesso scope senza errori — quindi una dichiarazione duplicata può sovrascrivere silenziosamente quella precedente. - Closure nei cicli: una variabile di ciclo
varvive in un unico scope di funzione condiviso, quindi ogni closure creata nel ciclo vede la stessa variabile. Quando le callback vengono eseguite, il ciclo è terminato e la variabile contiene il suo valore finale.
Il bug di closure nei cicli è il classico problema di var. Tutte e tre le callback condividono la stessa i:
Sostituire var con let risolve il problema: let crea un nuovo binding per ogni iterazione, quindi ogni closure cattura il proprio valore:
Prima di let, la soluzione era una IIFE che catturava il valore per ogni iterazione:
Introduzione di let e const
Per attenuare i problemi associati a var, let e const forniscono agli sviluppatori variabili con scope di blocco, riducendo il rischio di errori dovuti all'hoisting e rendendo il codice più prevedibile e più facile da debuggare.
Buone pratiche per l'uso di var in JavaScript
Nonostante le sue limitazioni, var rimane parte del linguaggio JavaScript e può ancora essere incontrata, soprattutto nel codice legacy. Il rispetto delle buone pratiche garantisce che il suo utilizzo non pregiudichi la funzionalità o la manutenibilità del codice.
- Limitare l'uso nel codice moderno: preferire
leteconstper le dichiarazioni di variabili, per sfruttare lo scope di blocco e ridurre i potenziali problemi di hoisting. - Comprendere lo scope: quando si lavora con
var, tenere presente la sua natura con scope di funzione e pianificare la struttura del codice di conseguenza per evitare variabili globali non intenzionali. - Inizializzazione al momento della dichiarazione: inizializzare le variabili
varal momento della dichiarazione per evitare valoriundefineddovuti all'hoisting.
Conclusione
La parola chiave var è stata a lungo un pilastro di JavaScript. Comprendere il suo comportamento di scoping e hoisting è fondamentale per scrivere codice affidabile. Con l'evoluzione del linguaggio, let e const sono stati introdotti per affrontare le limitazioni di var, rendendo JavaScript moderno più prevedibile. Tuttavia, comprendere var rimane essenziale per mantenere codebase legacy. Seguendo le buone pratiche e preferendo le dichiarazioni con scope di blocco, gli sviluppatori possono scrivere codice JavaScript più pulito e manutenibile.