L'instruction let
permet de déclarer une variable dont la portée est celle du bloc courant, éventuellement en initialisant sa valeur.
Syntaxe
let var1 [= valeur1] [, var2 [= valeur2]] [, ..., varN [= valeurN]];
Paramètres
var1
,var2
, …,varN
- Le nom de la variable. Cela peut être n'importe quel identifiant valide.
valeur1
,valeur2
, …,valeurN
- La valeur à utiliser pour initialiser la variable. Cela peut être n'importe quelle expression légale.
Description
let
permet de déclarer des variables dont la portée est limitée à celle du bloc dans lequel elles sont déclarées. Le mot-clé var
, quant à lui, permet de définir une variable globale ou locale à une fonction (sans distinction des blocs utilisés dans la fonction).
L'origine du nom let
est décrite dans cette réponse (en anglais).
Les portées de bloc avec let
Le mot-clé let
permet de définir des variables au sein d'un bloc.
if (x > y) { let gamma = 12.7 + y; i = gamma * x; }
Une meilleure lisibilité pour les fonctions internes
let
peut parfois permettre de rendre le code plus lisible lorsqu'on utilise des fonctions internes.
var list = document.getElementById("list"); for (let i = 1; i <= 5; i++) { let item = document.createElement("LI"); item.appendChild(document.createTextNode("Élément " + i)); item.onclick = function (ev) { console.log("Clic sur l'élément " + i + "."); }; list.appendChild(item); }
Dans l'exemple précédent, cela fonctionne comme on l'attend car les cinq instances de la fonction anonyme sont liées à cinq instances différentes de i
. Si on remplace let
par var
, on n'obtiendra pas l'effet escompté car on aura une même variable pour cette portée i=6
(au lieu de 5 différentes).
Règles de portées
Les variables déclarées avec let
appartiennent à la portée du bloc dans lequel elles sont définies et indirectement aux portées des blocs de ce bloc. D'une certaine façon let
fonctionne comme var
, la seule différence dans cette analogie est que let
fonctionne avec les portées de bloc et var
avec les portées des fonctions :
function varTest() { var x = 31; if (true) { var x = 71; // c'est la même variable ! console.log(x); // 71 } console.log(x); // 71 } function letTest() { let x = 31; if (true) { let x = 71; // c'est une variable différente console.log(x); // 71 } console.log(x); // 31 }
Au niveau le plus haut (la portée globale), let
crée une variable globale alors que var
ajoute une propriété à l'objet global :
var x = 'global'; let y = 'global2'; console.log(this.x); // "global" console.log(this.y); // undefine console.log(y); // "global2"
Émuler le fonctionnement des interfaces privées
En utilisant l'instruction let
avec des constructeurs, on peut créer des interfaces privées sans avoir à utiliser de fermetures :
var UnConstructeur; { let portéePrivée = {}; UnConstructeur = function UnConstructeur() { this.unePropriété = "toto"; portéePrivée.propCachée = "truc"; } UnConstructeur.prototype.affichePublic = function (){ console.log(this.unePropriété); // toto } UnConstructeur.prototype.affichePrivé = function (){ console.log(portéePrivée.propCachée); // truc } } var monInstance = new UnConstructeur(); monInstance.affichePublic(); monInstance.affichePrivé(); console.log(portéePrivée.propCachée); // erreur
Zone morte temporaire (temporal dead zone / TDZ) et les erreurs liées à let
Lorsqu'on redéclare une même variable au sein d'une même portée de bloc, cela entraîne une exception SyntaxError
.
if (x) { let toto; let toto; // SyntaxError }
Si on redéclare une variable pour le corps d'une fonction, cela ne pose aucun problème :
function faire_quelque_chose() { let toto; let toto; // Cela fonctionne. }
Avec ECMAScript 2015 (ES6), let
remontera la variable au début de la portée. Si on fait référence à une variable dans un bloc avant la déclaration de celle-ci avec let
, cela entraînera une exception ReferenceError
. En effet, la variable est placée dans une « zone morte temporaire » entre le début du bloc et le moment où la déclaration est traitée.
function faire_quelque_chose() { console.log(toto); // ReferenceError let toto = 2; }
Il est possible d'obtenir des erreurs au sein de l'instruction Instructions/switch
. En effet, il y a un seul bloc implicite pour cette instruction.
switch (x) { case 0: let toto; break; case 1: let toto; // SyntaxError for redeclaration. break; }
Si on utilise let
avec un nom de variable qui est le même que celui de l'argument passé à la fonction, on aura une erreur :
function go(n) { for (let n of n.a){ // TypeError: n is undefined console.log(n); } } go({a:[1, 2, 3]});
Les variables déclarées avec let
et les boucles for
Le mot-clé let
permet de lier des variables localement dans la portée des boucles for. Contrairement au mot-clé var qui lui rend les variables visibles depuis l'ensemble de la fonction qui contient la boucle.
var i=0; for ( let i=i ; i < 10 ; i++ ) { console.log(i); }
Règles de portées
for (let expr1; expr2; expr3) instruction
Dans cet exemple, expr2
, expr3
, et instruction
sont contenues dans un bloc implicite qui contient la variable de bloc local déclarée avec let expr1
.
Exemples
let
/ var
Lorsqu'il est utilisé dans un bloc, let
permet de limiter la portée de la variable à ce bloc. var quant à lui limite la portée de la variable à la fonction.
var a = 5; var b = 10; if (a === 5) { let a = 4; // La portée est celle du bloc if var b = 1; // La portée est celle interne à la fonction console.log(a); // 4 console.log(b); // 1 } console.log(a); // 5 console.log(b); // 1
let
utilisé dans les boucles
Le mot-clé let permet de lier des variables à la portée de la boucle plutôt qu'à celle de la fonction (avec var
) :
for (let i = 0; i<10; i++) { console.log(i); // 0, 1, 2, 3, 4 ... 9 } console.log(i); // i n'est pas défini
Spécifications
Spécification | État | Commentaires |
---|---|---|
ECMAScript 2015 (6th Edition, ECMA-262) La définition de 'Let and Const Declarations' dans cette spécification. |
Standard | Définition initiale. Cette définition n'inclue pas les expressions et blocs let . |
ECMAScript 2017 Draft (ECMA-262) La définition de 'Let and Const Declarations' dans cette spécification. |
Projet |
Compatibilité des navigateurs
Fonctionnalité | Chrome | Firefox (Gecko) | Edge | Internet Explorer | Opera | Safari |
---|---|---|---|---|---|---|
Support simple | 41.0 | 44 (44) | 12 | 11 | 17 | ? |
Zone morte temporaire (TDZ) | ? | 35 (35) | 12 | 11 | ? | ? |
Autorisé en mode non-strict | 49.0 | ? | 44 (44) | ? | ? | ? |
Fonctionnalité | Android | Chrome pour Android | Firefox Mobile (Gecko) | IE Mobile | Opera Mobile | Safari Mobile | |
---|---|---|---|---|---|---|---|
Support simple | ? | 41.0 | 44.0 (44) | ? | ? | ? | |
Zone morte temporaire (TDZ) | ? | ? | 35.0 (35) | ? | ? | ? | |
Autorisé en mode non-strict | Pas de support | 49.0 | 44 (44) | ? | ? | ? | 49.0 |
Notes spécifiques à Firefox
- Avant SpiderMonkey 46 (Firefox 46 / Thunderbird 46 / SeaMonkey 2.43), une exception
TypeError
était levée lorsqu'une variable était déclarée à nouveau (au lieu d'une exceptionSyntaxError
) (bug 1198833), bug 1275240). - Avant SpiderMonkey 44 (Firefox 44 / Thunderbird 44 / SeaMonkey 2.41),
let
était uniquement disponible dans les blocs de code HTML contenus dans un élément<script type="application/javascript;version=1.7">
(avec éventuellement une version supérieure) et la sémantique qui lui était associée était différente. - Le support de l'instruction dans le code des
Worker
est géré avec la préférencedom.workers.latestJSVersion
flag (bug 487070). Depuis quelet
n'est plus utilisé avec une version particulière de JavaScript, ce marqueur sera retiré prochainement (bug 1219523). - Pour SpiderMonkey, la conformité à ES6 pour l'instruction
let
est tracée dans le bug 950547