C'est le mot-clé avec lequel JavaScript a vécu pendant près de vingt ans. Tout le code écrit avant 2015 le contient, et il fonctionne encore : aucune version du langage ne l'a retiré, aucune ne le retirera.
Plus personne ne l'écrit pourtant dans du code neuf. Comprendre pourquoi en apprend davantage sur la façon dont JavaScript gère ses variables que n'importe quelle présentation de ses remplaçants.
Définition
var déclare une variable. Ce qui la distingue de let et de const n'est pas ce qu'elle peut contenir, mais deux règles héritées des premières versions du langage : elle existe dans toute la fonction qui la contient, et elle est créée avant que sa ligne de déclaration ne soit exécutée.
var devise = "EUR";
var devise = "USD"; // aucune erreur : la redéclaration est autorisée
console.log(devise); // "USD"Cette tolérance est le premier symptôme. Déclarer deux fois le même nom dans un même fichier est presque toujours une inattention, et var la laisse passer sans un mot.
Une portée de fonction, jamais de bloc
La portée d'une variable, c'est la zone de code où son nom est utilisable. Avec var, cette zone est la fonction entière, quel que soit l'endroit où la déclaration a été écrite. Les accolades d'un if ou d'un for ne l'arrêtent pas.
function total() {
var somme = 0;
for (var i = 0; i < 3; i++) {
somme += i;
}
return somme + i; // i existe encore ici, et il vaut 3
}
console.log(total()); // 6Le compteur a été déclaré dans l'en-tête de la boucle et il lui survit. Écrite avec let, la dernière ligne provoquerait une erreur, le nom disparaissant avec l'accolade fermante.
La variable existe avant sa propre ligne
Avant d'exécuter une fonction, le moteur y repère toutes les déclarations var et crée les variables correspondantes avec la valeur undefined. Seule l'affectation reste à sa place.
console.log(prix); // undefined, et non une erreur
var prix = 19;
console.log(prix); // 19Ce mécanisme, appelé remontée, explique une bonne part des bugs silencieux du JavaScript ancien : une faute de frappe sur un nom ne lève aucune erreur, elle produit une valeur vide qui ressort bien plus loin.
Une déclaration function remonte elle aussi, mais entièrement, corps compris. Une fonction déclarée en bas de fichier peut donc être appelée en haut, alors qu'une fonction rangée dans une variable var vaut undefined tant que l'affectation n'est pas passée.
Questions fréquentes
var est-il déprécié ?
Pas officiellement : aucune version d'ECMAScript ne l'a marqué obsolète, et le supprimer casserait une part immense du web existant. En pratique, les guides de style modernes l'interdisent dans le code neuf, et la règle no-var d'ESLint sert exactement à le signaler.
Que se passe-t-il si j'oublie le mot-clé ?
Hors mode strict, une affectation à un nom jamais déclaré crée une variable globale, visible depuis tout le programme. C'est une source de collisions dont le coupable est souvent dans un autre fichier. En mode strict, que tout module ES active automatiquement, la même ligne lève une erreur de référence.
Pourquoi mon compteur vaut-il la même valeur partout dans une boucle ?
Parce qu'avec var il n'existe qu'un seul compteur pour toute la boucle, partagé par les fonctions créées à l'intérieur. Toutes lisent sa valeur finale au moment où elles sont appelées, jamais celle du tour qui les a créées. Remplacer var par let dans l'en-tête suffit à obtenir 0, 1 et 2.
var fns = [];
for (var i = 0; i < 3; i++) fns.push(() => i);
console.log(fns[0](), fns[1](), fns[2]()); // 3 3 3