Arrivé avec ES2015, let a été conçu pour corriger un défaut précis : une variable qui débordait de l'endroit où on l'avait écrite. Le mot est court, le changement est profond.
Dans du code moderne, il n'y a plus que deux déclarations à connaître. let est celle qu'on prend quand la valeur va changer, et seulement dans ce cas.
Définition
let déclare une variable réaffectable dont la durée de vie s'arrête à l'accolade fermante du bloc qui la contient. Un bloc, ici, c'est n'importe quelle paire d'accolades : le corps d'une fonction, d'un if, d'une boucle, ou même une paire posée seule dans le code.
let panier = 0;
panier = 49; // réaffectation : autorisée
console.log(panier); // 49Ce qui n'est pas autorisé, c'est de redéclarer le même nom dans le même bloc. Une seconde ligne let panier ne se contente pas d'échouer à l'exécution : elle empêche le fichier entier d'être chargé, avec un message qui dit que le nom est déjà déclaré. C'est une bonne nouvelle, un doublon de ce genre étant toujours une erreur.
Une variable par bloc, une variable par tour
Deux noms identiques dans deux blocs différents désignent deux variables différentes, qui s'ignorent complètement.
let compteur = 0;
{
let compteur = 10; // une autre variable, dans un autre bloc
compteur += 1;
}
console.log(compteur); // 0La conséquence la plus utile concerne les boucles. Avec let, le compteur d'un for est recréé à chaque tour, si bien qu'une fonction créée pendant le parcours garde la valeur du tour où elle est née. Avec var, elles auraient toutes partagé le même compteur.
const sorties = [];
for (let i = 0; i < 3; i++) sorties.push(() => i);
console.log(sorties[0](), sorties[1](), sorties[2]()); // 0 1 2La zone morte temporaire
Le nom déclaré par let est bien connu du moteur dès l'entrée dans le bloc, mais il reste inutilisable jusqu'à sa ligne de déclaration. Cet intervalle porte un nom, la zone morte temporaire, et toute lecture qui s'y produit échoue.
console.log(taux); // ReferenceError: Cannot access 'taux' before initialization
let taux = 0.2;Le message est précis, et c'est tout l'intérêt : il distingue une variable lue trop tôt d'une variable qui n'existe pas du tout. Avec var, la même ligne aurait affiché undefined et le programme aurait continué avec une valeur vide.
Le mot « temporaire » est important. La zone morte n'est pas liée à la position dans le fichier mais à l'ordre d'exécution : une fonction écrite avant la déclaration peut parfaitement lire la variable, du moment qu'elle est appelée après.
Questions fréquentes
Faut-il utiliser let ou const par défaut ?
const par défaut, let uniquement quand la valeur doit être remplacée. Ce n'est pas une question de performance, les deux se valent : c'est une question de lecture. Voir let annonce au relecteur que la valeur va bouger, et cette information disparaît si on l'utilise partout.
Peut-on déclarer un let sans lui donner de valeur ?
Oui, et la variable vaut alors undefined jusqu'à sa première affectation. C'est le motif habituel quand la valeur dépend d'une condition qui n'est pas encore évaluée. Notez qu'un const n'a pas cette liberté : il exige une valeur sur sa propre ligne.
let fonctionne-t-il dans les anciens navigateurs ?
Tous les navigateurs maintenus le prennent en charge depuis longtemps, et la question ne se pose plus en pratique. Sur un projet qui doit viser des environnements très anciens, un outil de transpilation le réécrit en var en ajoutant les fonctions nécessaires pour préserver la portée de bloc.