web-dev-qa-db-fra.com

Quelle est la différence entre "let" et "var" pour déclarer une variable en JavaScript?

ECMAScript 6 a introduit la déclaration let . J'ai entendu dire que c'était une variable "locale", mais je ne sais toujours pas comment elle se comporte différemment du mot clé var.

Quelles sont les différences? Quand let devrait-il être utilisé par rapport à var?

3680
TM.

La différence est la portée. var est limité au bloc de fonction le plus proche et let est limité au bloc englobant le plus proche, qui peut être plus petit qu'un bloc de fonction Les deux sont globaux s'ils sont en dehors d'un bloc.

De plus, les variables déclarées avec let ne sont pas accessibles avant d'être déclarées dans leur bloc englobant. Comme on le voit dans la démo, une exception ReferenceError sera renvoyée.

Démo : 

var html = '';

write('#### global ####\n');
write('globalVar: ' + globalVar); //undefined, but visible

try {
  write('globalLet: ' + globalLet); //undefined, *not* visible
} catch (exception) {
  write('globalLet: exception');
}

write('\nset variables');

var globalVar = 'globalVar';
let globalLet = 'globalLet';

write('\nglobalVar: ' + globalVar);
write('globalLet: ' + globalLet);

function functionScoped() {
  write('\n#### function ####');
  write('\nfunctionVar: ' + functionVar); //undefined, but visible

  try {
    write('functionLet: ' + functionLet); //undefined, *not* visible
  } catch (exception) {
    write('functionLet: exception');
  }

  write('\nset variables');

  var functionVar = 'functionVar';
  let functionLet = 'functionLet';

  write('\nfunctionVar: ' + functionVar);
  write('functionLet: ' + functionLet);
}

function blockScoped() {
  write('\n#### block ####');
  write('\nblockVar: ' + blockVar); //undefined, but visible

  try {
    write('blockLet: ' + blockLet); //undefined, *not* visible
  } catch (exception) {
    write('blockLet: exception');
  }

  for (var blockVar = 'blockVar', blockIndex = 0; blockIndex < 1; blockIndex++) {
    write('\nblockVar: ' + blockVar); // visible here and whole function
  };

  for (let blockLet = 'blockLet', letIndex = 0; letIndex < 1; letIndex++) {
    write('blockLet: ' + blockLet); // visible only here
  };

  write('\nblockVar: ' + blockVar);

  try {
    write('blockLet: ' + blockLet); //undefined, *not* visible
  } catch (exception) {
    write('blockLet: exception');
  }
}

function write(line) {
  html += (line ? line : '') + '<br />';
}

functionScoped();
blockScoped();

document.getElementById('results').innerHTML = html;
<pre id="results"></pre>

Global:

Ils sont très similaires lorsqu'ils sont utilisés comme ceci en dehors d'un bloc de fonction.

let me = 'go';  // globally scoped
var i = 'able'; // globally scoped

Cependant, les variables globales définies avec let ne seront pas ajoutées en tant que propriétés sur l'objet global window comme celles définies avec var.

console.log(window.me); // undefined
console.log(window.i); // 'able'

Une fonction:

Ils sont identiques lorsqu'ils sont utilisés comme ceci dans un bloc de fonction.

function ingWithinEstablishedParameters() {
    let terOfRecommendation = 'awesome worker!'; //function block scoped
    var sityCheerleading = 'go!'; //function block scoped
}

Bloc:

Voici la différence. let n'est visible que dans la boucle for() et var est visible pour l'ensemble de la fonction.

function allyIlliterate() {
    //tuce is *not* visible out here

    for( let tuce = 0; tuce < 5; tuce++ ) {
        //tuce is only visible in here (and in the for() parentheses)
        //and there is a separate tuce variable for each iteration of the loop
    }

    //tuce is *not* visible out here
}

function byE40() {
    //nish *is* visible out here

    for( var nish = 0; nish < 5; nish++ ) {
        //nish is visible to the whole function
    }

    //nish *is* visible out here
}

Redéclaration:

En supposant le mode strict, var vous permettra de déclarer de nouveau la même variable dans la même portée. Par contre, let ne sera pas:

'use strict';
let me = 'foo';
let me = 'bar'; // SyntaxError: Identifier 'me' has already been declared
'use strict';
var me = 'foo';
var me = 'bar'; // No problem, `me` is replaced.
5094
ThinkingStiff

let peut également être utilisé pour éviter les problèmes de fermeture. Il lie une nouvelle valeur plutôt que de conserver une ancienne référence, comme indiqué dans les exemples ci-dessous.

D&EACUTE;MO

for(var i = 1; i < 6; i++) {
  document.getElementById('my-element' + i)
    .addEventListener('click', function() { alert(i) })
}

Le code ci-dessus illustre un problème classique de fermeture de JavaScript. La référence à la variable i est stockée dans la fermeture du gestionnaire de clics, plutôt que la valeur réelle de i.

Chaque gestionnaire de clic se réfère au même objet car il n’ya qu’un seul objet compteur qui en contient 6, de sorte que vous en obtenez six à chaque clic.

La solution de contournement générale consiste à envelopper cela dans une fonction anonyme et à passer i en argument. De tels problèmes peuvent également être évités maintenant en utilisant let à la place de var, comme indiqué dans le code ci-dessous.

DEMO (testé sous Chrome et Firefox 50)

'use strict';

for(let i = 1; i < 6; i++) {
  document.getElementById('my-element' + i)
    .addEventListener('click', function() { alert(i) })
}
505
Gurpreet Singh

Voici une explication du mot clé let avec quelques exemples.

laissez fonctionne très bien comme var. La principale différence est que la portée d'une variable var est la fonction englobante entière

Ce tableau sur Wikipedia indique les navigateurs prenant en charge Javascript 1.7.

Notez que seuls les navigateurs Mozilla et Chrome le prennent en charge. IE, Safari et potentiellement d'autres ne le font pas.

138
Ben S

Quelle est la différence entre let et var?

  • Une variable définie à l'aide d'une instruction var est connue dans tout le répertoire de la fonction dans laquelle elle est définie depuis le début de la fonction. (*)
  • Une variable définie à l'aide d'une instruction let n'est connue que dans le bloc il est défini dans, à partir du moment où elle est définie. _ {(**)} _

Pour comprendre la différence, considérons le code suivant:

// i IS NOT known here
// j IS NOT known here
// k IS known here, but undefined
// l IS NOT known here

function loop(arr) {
    // i IS known here, but undefined
    // j IS NOT known here
    // k IS known here, but has a value only the second time loop is called
    // l IS NOT known here

    for( var i = 0; i < arr.length; i++ ) {
        // i IS known here, and has a value
        // j IS NOT known here
        // k IS known here, but has a value only the second time loop is called
        // l IS NOT known here
    };

    // i IS known here, and has a value
    // j IS NOT known here
    // k IS known here, but has a value only the second time loop is called
    // l IS NOT known here

    for( let j = 0; j < arr.length; j++ ) {
        // i IS known here, and has a value
        // j IS known here, and has a value
        // k IS known here, but has a value only the second time loop is called
        // l IS NOT known here
    };

    // i IS known here, and has a value
    // j IS NOT known here
    // k IS known here, but has a value only the second time loop is called
    // l IS NOT known here
}

loop([1,2,3,4]);

for( var k = 0; k < arr.length; k++ ) {
    // i IS NOT known here
    // j IS NOT known here
    // k IS known here, and has a value
    // l IS NOT known here
};

for( let l = 0; l < arr.length; l++ ) {
    // i IS NOT known here
    // j IS NOT known here
    // k IS known here, and has a value
    // l IS known here, and has a value
};

loop([1,2,3,4]);

// i IS NOT known here
// j IS NOT known here
// k IS known here, and has a value
// l IS NOT known here

Ici, nous pouvons voir que notre variable j n'est connue que dans la première boucle for, mais pas avant et après. Cependant, notre variable i est connue dans toute la fonction.

En outre, considérez que les variables de portée de bloc ne sont pas connues avant leur déclaration car elles ne sont pas levées. Vous n'êtes également pas autorisé à redéclarer la même variable de périmètre de bloc dans le même bloc. Cela rend les variables à portée de bloc moins sujettes aux erreurs que les variables à portée globale ou fonctionnelle, qui sont levées et qui ne produisent aucune erreur en cas de déclarations multiples.


Est-il prudent d'utiliser let aujourd'hui?

Certains diront qu'à l'avenir, nous utiliserons UNIQUEMENT les instructions let et que les instructions var deviendront obsolètes. Gourou JavaScript Kyle Simpson a écrit un article très élaboré expliquant pourquoi ce n'est pas le cas .

Aujourd'hui, cependant, ce n'est définitivement pas le cas. En fait, nous devons nous demander s'il est prudent d'utiliser l'instruction let. La réponse à cette question dépend de votre environnement:

  • Si vous écrivez du code JavaScript côté serveur ( Node.js ), vous pouvez utiliser en toute sécurité l'instruction let.

  • Si vous écrivez du code JavaScript côté client et utilisez un transpiler (comme Traceur ), vous pouvez utiliser l'instruction let en toute sécurité, mais votre code sera probablement tout sauf optimal en termes de performances.

  • Si vous écrivez du code JavaScript côté client et n'utilisez pas de transpiler, vous devez envisager la prise en charge du navigateur.

Aujourd'hui, 8 juin 2018, il reste encore des navigateurs qui ne supportent pas let!

 enter image description here


Comment suivre le support du navigateur

Pour un aperçu à jour des navigateurs qui prennent en charge l'instruction let au moment de lire cette réponse, voir this Can I Use page .


(*)) Les variables à portée globale et fonctionnelle peuvent être initialisées et utilisées avant d'être déclarées, car les variables JavaScript sont hoisted . Cela signifie que les déclarations sont toujours beaucoup plus en haut .

(**) Les variables de périmètre de bloc ne sont pas levées}

135
John Slegers

La réponse acceptée manque un point:

{
  let a = 123;
};

console.log(a); // ReferenceError: a is not defined
104
Lcf.vs

let

Bloquer la portée

Les variables déclarées à l'aide du mot clé let ont une portée de bloc, ce qui signifie qu'elles ne sont disponibles que dans le bloc block dans lequel elles ont été déclarées.

Au niveau supérieur (en dehors d'une fonction)

Au niveau supérieur, les variables déclarées à l'aide de let ne créent pas de propriétés sur l'objet global.

var globalVariable = 42;
let blockScopedVariable = 43;

console.log(globalVariable); // 42
console.log(blockScopedVariable); // 43

console.log(this.globalVariable); // 42
console.log(this.blockScopedVariable); // undefined

À l'intérieur d'une fonction

Dans une fonction (mais en dehors d'un bloc), let a la même portée que var.

(() => {
  var functionScopedVariable = 42;
  let blockScopedVariable = 43;

  console.log(functionScopedVariable); // 42
  console.log(blockScopedVariable); // 43
})();

console.log(functionScopedVariable); // ReferenceError: functionScopedVariable is not defined
console.log(blockScopedVariable); // ReferenceError: blockScopedVariable is not defined

À l'intérieur d'un bloc

Les variables déclarées à l'aide de let à l'intérieur d'un bloc sont inaccessibles en dehors de ce bloc.

{
  var globalVariable = 42;
  let blockScopedVariable = 43;
  console.log(globalVariable); // 42
  console.log(blockScopedVariable); // 43
}

console.log(globalVariable); // 42
console.log(blockScopedVariable); // ReferenceError: blockScopedVariable is not defined

Dans une boucle

Les variables déclarées avec let dans les boucles ne peuvent être référencées qu'à l'intérieur de cette boucle.

for (var i = 0; i < 3; i++) {
  var j = i * 2;
}
console.log(i); // 3
console.log(j); // 4

for (let k = 0; k < 3; k++) {
  let l = k * 2;
}
console.log(typeof k); // undefined
console.log(typeof l); // undefined
// Trying to do console.log(k) or console.log(l) here would throw a ReferenceError.

Boucles avec des fermetures

Si vous utilisez let au lieu de var dans une boucle, vous obtenez une nouvelle variable à chaque itération. Cela signifie que vous pouvez utiliser en toute sécurité une fermeture dans une boucle.

// Logs 3 thrice, not what we meant.
for (var i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 0);
}

// Logs 0, 1 and 2, as expected.
for (let j = 0; j < 3; j++) {
  setTimeout(() => console.log(j), 0);
}

Zone morte temporelle

En raison de la zone morte temporelle , les variables déclarées à l'aide de let ne sont pas accessibles avant d'être déclarées. Tenter de le faire renvoie une erreur.

console.log(noTDZ); // undefined
var noTDZ = 43;
console.log(hasTDZ); // ReferenceError: hasTDZ is not defined
let hasTDZ = 42;

Pas de re-déclaration

Vous ne pouvez pas déclarer la même variable plusieurs fois à l'aide de let. Vous ne pouvez pas non plus déclarer une variable à l'aide de let avec le même identifiant qu'une autre variable déclarée à l'aide de var.

var a;
var a; // Works fine.

let b;
let b; // SyntaxError: Identifier 'b' has already been declared

var c;
let c; // SyntaxError: Identifier 'c' has already been declared

const

const est assez similaire à let— il a une portée de bloc et a TDZ. Il y a cependant deux choses différentes.

Pas de réaffectation

La variable déclarée à l'aide de const ne peut pas être réaffectée.

const a = 42;
a = 43; // TypeError: Assignment to constant variable.

Notez que cela ne signifie pas que la valeur est immuable. Ses propriétés peuvent encore être modifiées.

const obj = {};
obj.a = 42;
console.log(obj.a); // 42

Si vous voulez avoir un objet immuable, vous devez utiliser Object.freeze() .

L'initialiseur est requis

Vous devez toujours spécifier une valeur lors de la déclaration d'une variable à l'aide de const.

const a; // SyntaxError: Missing initializer in const declaration
59

Voici un exemple de la différence entre les deux (support qui vient de commencer pour chrome): enter image description here

Comme vous pouvez le constater, la variable var j a toujours une valeur en dehors de l'étendue de la boucle for, mais la variable let i n'est pas définie en dehors de l'étendue de la boucle for.

"use strict";
console.log("var:");
for (var j = 0; j < 2; j++) {
  console.log(j);
}

console.log(j);

console.log("let:");
for (let i = 0; i < 2; i++) {
  console.log(i);
}

console.log(i);

42
vlio20

Il existe quelques différences subtiles - la portée de let se comporte davantage comme le fait la portée de variable dans plus ou moins d’autres langues. 

par exemple. Cela concerne le bloc englobant, ils n'existent pas avant leur déclaration, etc.

Toutefois, il est à noter que let n'est qu'une partie des implémentations Javascript plus récentes et prend en charge divers degrés de support pour browser .

42
olliej
  • Variable non levante

    letne relancera pas à toute l'étendue du bloc dans lequel ils apparaissent. En revanche, var pourrait remonter comme ci-dessous.

    {
       console.log(cc); // undefined. Caused by hoisting
       var cc = 23;
    }
    
    {
       console.log(bb); // ReferenceError: bb is not defined
       let bb = 23;
    }
    

    En fait, Per @Bergi, var et let sont tous deux hissés .

  • Collecte des ordures

    La portée du bloc de let est utile pour les fermetures et le garbage collection afin de récupérer la mémoire. Considérer,

    function process(data) {
        //...
    }
    
    var hugeData = { .. };
    
    process(hugeData);
    
    var btn = document.getElementById("mybutton");
    btn.addEventListener( "click", function click(evt){
        //....
    });
    

    Le rappel du gestionnaire click n'a pas du tout besoin de la variable hugeData. Théoriquement, après l'exécution de process(..), l'énorme structure de données hugeData pourrait être récupérée. Cependant, il est possible que certains moteurs JS doivent encore conserver cette structure énorme, car la fonction click a une fermeture sur toute la portée.

    Cependant, la portée du bloc peut transformer cette énorme structure de données en déchets.

    function process(data) {
        //...
    }
    
    { // anything declared inside this block can be garbage collected
        let hugeData = { .. };
        process(hugeData);
    }
    
    var btn = document.getElementById("mybutton");
    btn.addEventListener( "click", function click(evt){
        //....
    });
    
  • let boucles

    let dans la boucle peut le relier à chaque itération de la boucle, en s'assurant de la réaffecter à la valeur à partir de la fin de l'itération de la boucle précédente. Considérer,

    // print '5' 5 times
    for (var i = 0; i < 5; ++i) {
        setTimeout(function () {
            console.log(i);
        }, 1000);  
    }
    

    Cependant, remplacez var par let

    // print 1, 2, 3, 4, 5. now
    for (let i = 0; i < 5; ++i) {
        setTimeout(function () {
            console.log(i);
        }, 1000);  
    }
    

    Parce que let crée un nouvel environnement lexical avec ces noms pour a) l'expression d'initialiseur b) chaque itération (avant d'évaluer l'évaluation d'incrémentation), plus de détails sont ici .

20
zangw

La différence principale est la différence scope, alors que let ne peut être disponible qu'à l'intérieur du scope déclaré, comme dans la boucle for, var est accessible en dehors de la boucle par exemple. . De la documentation dans MDN (exemples également de MDN):

let vous permet de déclarer des variables dont la portée est limitée au bloc, à l'instruction ou à l'expression sur lequel elles sont utilisées. Cela diffère du mot-clé var, qui définit une variable globalement ou localement sur une fonction entière, quelle que soit la portée du bloc.

Les variables déclarées par let ont pour portée le bloc dans lequel elles sont définies, ainsi que dans tous les sous-blocs contenus. De cette façon, let fonctionne très bien comme var. La principale différence est que la portée d'une variable var correspond à l'ensemble de la fonction englobante:

function varTest() {
  var x = 1;
  if (true) {
    var x = 2;  // same variable!
    console.log(x);  // 2
  }
  console.log(x);  // 2
}

function letTest() {
  let x = 1;
  if (true) {
    let x = 2;  // different variable
    console.log(x);  // 2
  }
  console.log(x);  // 1
}`

Au niveau supérieur des programmes et des fonctions, let, contrairement à var, ne crée pas de propriété sur l'objet global. Par exemple:

var x = 'global';
let y = 'global';
console.log(this.x); // "global"
console.log(this.y); // undefined

Lorsqu'il est utilisé à l'intérieur d'un bloc, laisse limiter la portée de la variable à ce bloc. Notez la différence entre var dont la portée est à l'intérieur de la fonction où elle est déclarée.

var a = 1;
var b = 2;

if (a === 1) {
  var a = 11; // the scope is global
  let b = 22; // the scope is inside the if-block

  console.log(a);  // 11
  console.log(b);  // 22
} 

console.log(a); // 11
console.log(b); // 2

N'oubliez pas non plus que c'est la fonctionnalité ECMA6, donc elle n'est pas encore totalement prise en charge. Il est donc préférable de toujours l'envoyer à ECMA5 avec Babel, etc. Pour plus d'informations sur visit babel website

18
Alireza

Voici un exemple à ajouter à ce que d’autres ont déjà écrit. Supposons que vous souhaitiez créer un tableau de fonctions, adderFunctions, où chaque fonction prend un seul argument Number et renvoie la somme de l'argument et l'index de la fonction dans le tableau. Essayer de générer adderFunctions avec une boucle en utilisant le mot clé var ne fonctionnera pas comme quelqu'un pourrait s'y attendre naïvement:

// An array of adder functions.
var adderFunctions = [];

for (var i = 0; i < 1000; i++) {
  // We want the function at index i to add the index to its argument.
  adderFunctions[i] = function(x) {
    // What is i bound to here?
    return x + i;
  };
}

var add12 = adderFunctions[12];

// Uh oh. The function is bound to i in the outer scope, which is currently 1000.
console.log(add12(8) === 20); // => false
console.log(add12(8) === 1008); // => true
console.log(i); // => 1000

// It gets worse.
i = -8;
console.log(add12(8) === 0); // => true

Le processus ci-dessus ne génère pas le tableau de fonctions souhaité, car la portée de i s'étend au-delà de l'itération du bloc for dans lequel chaque fonction a été créée. Au lieu de cela, à la fin de la boucle, la i dans la fermeture de chaque fonction fait référence à la valeur de i à la fin de la boucle (1000) pour chaque fonction anonyme dans adderFunctions. Ce n’était pas ce que nous voulions du tout: nous avons maintenant en mémoire un tableau de 1000 fonctions différentes avec exactement le même comportement. Et si nous mettons ensuite à jour la valeur de i, la mutation affectera tous les adderFunctions.

Cependant, nous pouvons essayer à nouveau en utilisant le mot clé let:

// Let's try this again.
// NOTE: We're using another ES6 keyword, const, for values that won't
// be reassigned. const and let have similar scoping behavior.
const adderFunctions = [];

for (let i = 0; i < 1000; i++) {
  // NOTE: We're using the newer arrow function syntax this time, but 
  // using the "function(x) { ..." syntax from the previous example 
  // here would not change the behavior shown.
  adderFunctions[i] = x => x + i;
}

const add12 = adderFunctions[12];

// Yay! The behavior is as expected. 
console.log(add12(8) === 20); // => true

// i's scope doesn't extend outside the for loop.
console.log(i); // => ReferenceError: i is not defined

Cette fois, i est rebondi à chaque itération de la boucle for. Chaque fonction conserve maintenant la valeur de i au moment de sa création et adderFunctions se comporte comme prévu.

Maintenant, en mélangeant les deux comportements, vous comprendrez probablement pourquoi il est déconseillé de mélanger les nouvelles variables let et const avec les anciennes var dans le même script. Cela peut donner lieu à un code extrêmement confus.

const doubleAdderFunctions = [];

for (var i = 0; i < 1000; i++) {
    const j = i;
    doubleAdderFunctions[i] = x => x + i + j;
}

const add18 = doubleAdderFunctions[9];
const add24 = doubleAdderFunctions[12];

// It's not fun debugging situations like this, especially when the
// code is more complex than in this example.
console.log(add18(24) === 42); // => false
console.log(add24(18) === 42); // => false
console.log(add18(24) === add24(18)); // => false
console.log(add18(24) === 2018); // => false
console.log(add24(18) === 2018); // => false
console.log(add18(24) === 1033); // => true
console.log(add24(18) === 1030); // => true

Ne laissez pas cela vous arriver. Utilisez un linter.

NOTE: Ceci est un exemple pédagogique destiné à démontrer le comportement var/let dans les boucles et avec des fermetures de fonctions faciles à comprendre. Ce serait un moyen terrible d'ajouter des chiffres. Mais la technique générale de capture de données dans des fermetures de fonctions anonymes peut être rencontrée dans le monde réel dans d'autres contextes. YMMV.

14
abroz

La différence est dans le scope des variables déclarées avec chacune.

En pratique, la différence de portée a plusieurs conséquences utiles:

  1. Les variables let ne sont visibles que dans leur bloc le plus proche englobant _ ({ ... }).
  2. Les variables let ne sont utilisables que dans les lignes de code qui apparaissent après la variable est déclarée (même si elles sont levées !).
  3. Les variables let ne peuvent pas être redéclarées par un var ou un let suivant.
  4. Les variables globales let ne sont pas ajoutées à l'objet global window.
  5. Les variables let sont faciles à utiliser avec fermetures (elles ne provoquent pas conditions de concurrence ).

Les restrictions imposées par let réduisent la visibilité des variables et augmentent la probabilité que des collisions de noms inattendues soient détectées plus tôt. Cela facilite le suivi et le raisonnement des variables, y compris leur accessibilité (aidant à récupérer la mémoire inutilisée).

Par conséquent, les variables let sont moins susceptibles de poser des problèmes lorsqu'elles sont utilisées dans des programmes volumineux ou lorsque des cadres développés indépendamment sont combinés de manière nouvelle et inattendue.

var peut toujours être utile si vous êtes certain de vouloir l'effet de liaison unique lorsque vous utilisez une fermeture dans une boucle (# 5) ou pour déclarer des variables globales visibles de l'extérieur dans votre code (# 4). L'utilisation de var pour les exportations peut être remplacée si export migre hors de l'espace du transpiler et dans la langue principale.

Exemples

1. Aucune utilisation en dehors du bloc englobant le plus proche: Ce bloc de code génère une erreur de référence car la deuxième utilisation de x se produit en dehors du bloc où il est déclaré avec let:

{
    let x = 1;
}
console.log(`x is ${x}`);  // ReferenceError during parsing: "x is not defined".

En revanche, le même exemple avec var fonctionne.

2. Aucune utilisation avant déclaration:
Ce bloc de code lancera une ReferenceError avant que le code puisse être exécuté car x est utilisé avant sa déclaration: 

{
    x = x + 1;  // ReferenceError during parsing: "x is not defined".
    let x;
    console.log(`x is ${x}`);  // Never runs.
}

En revanche, le même exemple avec var analyse et s'exécute sans exception.

3. Pas de nouvelle déclaration: Le code suivant montre qu'une variable déclarée avec let ne peut pas être redéclarée ultérieurement: 

let x = 1;
let x = 2;  // SyntaxError: Identifier 'x' has already been declared

4. Globals non attachés à window:

var button = "I cause accidents because my name is too common.";
let link = "Though my name is common, I am harder to access from other JS files.";
console.log(link);  // OK
console.log(window.link);  // undefined (GOOD!)
console.log(window.button);  // OK

5. Utilisation facile avec des fermetures: Les variables déclarées avec var ne fonctionnent pas bien avec les fermetures à l'intérieur des boucles. Voici une boucle simple qui sort la séquence de valeurs que la variable i a à différents moments dans le temps: 

for (let i = 0; i < 5; i++) {
    console.log(`i is ${i}`), 125/*ms*/);
}

Plus précisément, cela génère:

i is 0
i is 1
i is 2
i is 3
i is 4

En JavaScript, nous utilisons souvent des variables beaucoup plus tard que lors de leur création. Lorsque nous démontrons cela en retardant la sortie avec une fermeture passée à setTimeout

for (let i = 0; i < 5; i++) {
    setTimeout(_ => console.log(`i is ${i}`), 125/*ms*/);
}

... la sortie reste inchangée tant que nous nous en tenons à let. En revanche, si nous avions utilisé var i à la place: 

for (var i = 0; i < 5; i++) {
    setTimeout(_ => console.log(`i is ${i}`), 125/*ms*/);
}

... la boucle génère inopinément "i is 5" cinq fois:

i is 5
i is 5
i is 5
i is 5
i is 5
11
mormegil

Puissent les deux fonctions suivantes montrer la différence:

function varTest() {
    var x = 31;
    if (true) {
        var x = 71;  // Same variable!
        console.log(x);  // 71
    }
    console.log(x);  // 71
}

function letTest() {
    let x = 31;
    if (true) {
        let x = 71;  // Different variable
        console.log(x);  // 71
    }
    console.log(x);  // 31
}
10
Abdennour TOUMI

let est intéressant, car cela nous permet de faire quelque chose comme ceci:

(() => {
    var count = 0;

    for (let i = 0; i < 2; ++i) {
        for (let i = 0; i < 2; ++i) {
            for (let i = 0; i < 2; ++i) {
                console.log(count++);
            }
        }
    }
})();

Ce qui entraîne le comptage [0, 7].

Tandis que

(() => {
    var count = 0;

    for (var i = 0; i < 2; ++i) {
        for (var i = 0; i < 2; ++i) {
            for (var i = 0; i < 2; ++i) {
                console.log(count++);
            }
        }
    }
})();

Ne compte que [0, 1].

10
Dmitry

Portée du bloc de fonction VS:

La principale différence entre var et let est que les variables déclarées avec var sont function scoped . Alors que les fonctions déclarées avec let sont block scoped . Par exemple:

function testVar () {
  if(true) {
    var foo = 'foo';
  }

  console.log(foo);
}

testVar();  
// logs 'foo'


function testLet () {
  if(true) {
    let bar = 'bar';
  }

  console.log(bar);
}

testLet(); 
// reference error
// bar is scoped to the block of the if statement 

variables avec var:

Lorsque la première fonction testVar est appelée la variable foo, déclarée avec var, elle est toujours accessible en dehors de l'instruction if. Cette variable foo serait disponible partout dans le cadre de la testVar fonction .

variables avec let:

Lorsque la deuxième fonction testLet est appelée barre de variable, déclarée avec let, elle n'est accessible que dans l'instruction if. Comme les variables déclarées avec let sont block scoped (où un bloc est le code entre accolades, par exemple if{}, for{}, function{}). 

Les variables let ne sont pas levées:

Une autre différence entre var et let concerne les variables avec déclaré avec let ne pas se hisser . Un exemple est le meilleur moyen d’illustrer ce comportement:

variables avec let ne pas se hisser:

console.log(letVar);

let letVar = 10;
// referenceError, the variable doesn't get hoisted

variables avec var do get hisse:

console.log(varVar);

var varVar = 10;
// logs undefined, the variable gets hoisted

La variable globale let ne s'attache pas à window:

Une variable déclarée avec let dans la portée globale (qui est un code qui n'est pas dans une fonction) n'est pas ajoutée en tant que propriété sur l'objet global window. Par exemple (ce code est dans la portée globale):

var bar = 5;
let foo  = 10;

console.log(bar); // logs 5
console.log(foo); // logs 10

console.log(window.bar);  
// logs 5, variable added to window object

console.log(window.foo);
// logs undefined, variable not added to window object


Dans quels cas let devrait-il être utilisé sur var?

Utilisez let sur var chaque fois que vous le pouvez, car la portée est plus précise. Cela réduit les conflits de noms potentiels pouvant survenir lors du traitement d'un grand nombre de variables. var peut être utilisé lorsque vous souhaitez qu'une variable globale soit explicitement sur l'objet window (réfléchissez toujours si cela est vraiment nécessaire). 

8

Il semble également que, au moins dans Visual Studio 2015, TypeScript 1.5, "var" autorise plusieurs déclarations du même nom de variable dans un bloc et "let" ne le permette pas.

Cela ne générera pas d'erreur de compilation:

var x = 1;
var x = 2;

Cette volonté:

let x = 1;
let x = 2;
6
RDoc

var est une variable de portée globale (pouvant être levée).

let et const est une étendue de bloc.

test.js

{
    let l = 'let';
    const c = 'const';
    var v = 'var';
    v2 = 'var 2';
}

console.log(v, this.v);
console.log(v2, this.v2);
console.log(l); // ReferenceError: l is not defined
console.log(c); // ReferenceError: c is not defined

5
Moslem Shahsavan

Lors de l'utilisation de let

Le mot clé let attache la déclaration de variable à la portée de n'importe quel bloc (généralement une paire { .. }) dans laquelle elle est contenue. En d'autres termes, let pirate implicitement la portée de la déclaration d'une variable.

Les variables let ne sont pas accessibles dans l'objet window car elles ne peuvent pas être accessibles globalement.

function a(){
    { // this is the Max Scope for let variable
        let x = 12;
    }
    console.log(x);
}
a(); // Uncaught ReferenceError: x is not defined

Lors de l'utilisation de var

var et les variables dans ES5 ont des portées dans les fonctions, ce qui signifie que les variables sont valides dans la fonction et non en dehors de la fonction elle-même.

Les variables var sont accessibles dans l'objet window car elles ne peuvent pas être accessibles globalement.

function a(){ // this is the Max Scope for var variable
    { 
        var x = 12;
    }
    console.log(x);
}
a(); // 12

Si vous voulez en savoir plus, continuez à lire ci-dessous

l’une des questions d’interview les plus connues sur la portée peut également suffire à l’utilisation exacte de let et var comme ci-dessous;

Si vous utilisez let

for (let i = 0; i < 10 ; i++) {
    setTimeout(
        function a() {
            console.log(i); //print 0 to 9, that is literally AWW!!!
        }, 
        100 * i);
}

En effet, lorsque vous utilisez let, la variable est étendue et a sa propre copie pour chaque itération de boucle.

Si vous utilisez var

for (var i = 0; i < 10 ; i++) {
    setTimeout(
        function a() {
            console.log(i); //print 10 times 10
        }, 
        100 * i);
}

En effet, lorsque vous utilisez var, la variable est étendue et a une copie partagée pour chaque itération de boucle.

4
Ankur Soni

Si j’ai bien lu les spécifications, alors letheureusement peut aussi être utilisé pour éviter des fonctions invoquant elles-mêmes utilisées pour simuler des membres privés uniquement - un modèle de conception populaire qui diminue la lisibilité du code, complique le aucune protection de code réelle ou autre avantage - sauf peut-être satisfaire le désir de sémantique de quelqu'un, alors arrêtez de l'utiliser./rant}

var SomeConstructor;

{
    let privateScope = {};

    SomeConstructor = function SomeConstructor () {
        this.someProperty = "foo";
        privateScope.hiddenProperty = "bar";
    }

    SomeConstructor.prototype.showPublic = function () {
        console.log(this.someProperty); // foo
    }

    SomeConstructor.prototype.showPrivate = function () {
        console.log(privateScope.hiddenProperty); // bar
    }

}

var myInstance = new SomeConstructor();

myInstance.showPublic();
myInstance.showPrivate();

console.log(privateScope.hiddenProperty); // error

Voir ' Emulation d'interfaces privées '

4
Daniel Sokolowski

Quelques hacks avec let:

1.

    let statistics = [16, 170, 10];
    let [age, height, grade] = statistics;

    console.log(height)

2.

    let x = 120,
    y = 12;
    [x, y] = [y, x];
    console.log(`x: ${x} y: ${y}`);

3.

    let node = {
                   type: "Identifier",
                   name: "foo"
               };

    let { type, name, value } = node;

    console.log(type);      // "Identifier"
    console.log(name);      // "foo"
    console.log(value);     // undefined

    let node = {
        type: "Identifier"
    };

    let { type: localType, name: localName = "bar" } = node;

    console.log(localType);     // "Identifier"
    console.log(localName);     // "bar"

Getter et setter avec let:

let jar = {
    numberOfCookies: 10,
    get cookies() {
        return this.numberOfCookies;
    },
    set cookies(value) {
        this.numberOfCookies = value;
    }
};

console.log(jar.cookies)
jar.cookies = 7;

console.log(jar.cookies)
3
zloctb

let est une partie de es6. Ces fonctions expliqueront la différence de manière simple.

function varTest() {
  var x = 1;
  if (true) {
    var x = 2;  // same variable!
    console.log(x);  // 2
  }
  console.log(x);  // 2
}

function letTest() {
  let x = 1;
  if (true) {
    let x = 2;  // different variable
    console.log(x);  // 2
  }
  console.log(x);  // 1
}
2
vipul jain

Auparavant, il n’existait que deux champs d’application en JavaScript, à savoir fonctionnel et global. Avec le mot clé 'let', JavaScript a maintenant introduit les variables block-level.

Pour bien comprendre le mot clé 'let', ES6: Le mot clé 'let' permettant de déclarer une variable en JavaScript vous aidera.

1
Hitesh Garg

Cet article définit clairement la différence entre var, let et const

const indique que l’identificateur ne sera pas réaffecté.

let, indique que la variable peut être réaffectée, telle qu'un compteur dans une boucle, ou un échange de valeur dans un algorithme. Il signale également que la variable ne sera utilisée que dans le bloc dans lequel elle est définie, qui n'est pas toujours la totalité de la fonction contenant.

var est maintenant le signal le plus faible disponible lorsque vous définissez une variable en JavaScript. La variable peut ou non être réaffectée, et le variable peut ou peut ne pas être utilisé pour une fonction entière, ou simplement pour le but d'un bloc ou d'une boucle.

https://medium.com/javascript-scene/javascript-es6-var-let-or-const-ba58b8dcde75#.esmkpbg9b

1
anandharshan

Maintenant, je pense que les variables sont mieux ciblées sur un bloc d'instructions utilisant let:

function printnums()
{
    // i is not accessible here
    for(let i = 0; i <10; i+=)
    {
       console.log(i);
    }
    // i is not accessible here

    // j is accessible here
    for(var j = 0; j <10; j++)
    {
       console.log(j);
    }
    // j is accessible here
}

Je pense que les gens vont commencer à utiliser let here after afin d'avoir une portée similaire à JavaScript, à l'instar d'autres langages, Java, C #, etc.

Les personnes qui ne comprenaient pas bien la portée de JavaScript avaient l'habitude de faire l'erreur plus tôt.

Le levage n'est pas pris en charge avec let.

Avec cette approche, les erreurs présentes dans JavaScript sont supprimées. 

Reportez-vous à ES6 In Depth: let et const pour mieux le comprendre.

1
swaraj patil

laissez vs var. Tout tourne autour de scope .

Les variables var sont globales et sont accessibles pratiquement partout, alors que les variables ne sont pas globales et n'existent que jusqu'à ce qu'une parenthèse fermante les tue.

Voir mon exemple ci-dessous et notez comment la variable lion (let) agit différemment dans les deux consoles.logs; il devient hors de portée dans le 2nd console.log.

var cat = "cat";
let dog = "dog";

var animals = () => {
    var giraffe = "giraffe";
    let lion = "lion";

    console.log(cat);  //will print 'cat'.
    console.log(dog);  //will print 'dog', because dog was declared outside this function (like var cat).

    console.log(giraffe); //will print 'giraffe'.
    console.log(lion); //will print 'lion', as lion is within scope.
}

console.log(giraffe); //will print 'giraffe', as giraffe is a global variable (var).
console.log(lion); //will print UNDEFINED, as lion is a 'let' variable and is now out of scope.
1
daCoda

Comme mentionné ci-dessus:

La différence est la portée. var est affecté au fonction bloc le plus proche et let est associé au bloc englobant le plus proche, lequel peut être plus petit qu'un bloc de fonction. Les deux sont globaux si en dehors de block.Lets un exemple:

Exemple 1:

Dans mes deux exemples, j'ai une fonction myfunc. myfunc contient une variable myvar égale à 10. Dans mon premier exemple, je vérifie si myvar est égal à 10 (myvar==10). Si oui, j’ai déclaré une variable myvar (maintenant j’ai deux variables myvar) en utilisant le mot clé var et lui attribue une nouvelle valeur (20). Dans la ligne suivante, j'imprime sa valeur sur ma console. Après le bloc conditionnel, j'imprime à nouveau la valeur myvar sur ma console. Si vous regardez le résultat de myfunc, myvar a une valeur égale à 20. 

 let keyword

Exemple2: Dans mon deuxième exemple, au lieu d'utiliser le mot clé var dans mon bloc conditionnel, je déclare myvar à l'aide du mot clé let. Maintenant, lorsque j'appelle myfunc, j'obtiens deux sorties différentes: myvar=20 et myvar=10.

La différence est donc très simple, c'est-à-dire sa portée. 

1
N Randhawa

 enter image description here

Regardez cette image, j'ai créé un exemple très simple pour la démonstration des variables const et let. Comme vous pouvez le constater, lorsque vous essayez de modifier la variable const, vous obtenez le message d'erreur (Essayer de remplacer le nom 'qui est constant'), mais jetez un coup d'œil à la variable let ... 

D'abord, nous déclarons let age = 33, et plus tard, nous affectons une autre valeur age = 34;, ce qui est correct. Nous n'avons pas d'erreur lorsque nous essayons de modifier la variable let.

0
Mile Mijatovic

Je souhaite lier ces mots-clés au contexte d'exécution, car le contexte d'exécution est important dans tout cela. Le contexte d'exécution comporte deux phases: une phase de création et une phase d'exécution. De plus, chaque contexte d'exécution comporte un environnement variable et un environnement externe (son environnement lexical).

Au cours de la phase de création d’un contexte d’exécution, var, let et const conservent toujours sa variable en mémoire avec une valeur non définie dans l’environnement de variable du contexte d’exécution donné. La différence est dans la phase d'exécution. Si vous utilisez la référence d'une variable définie avec var avant qu'une valeur ne lui soit affectée, elle sera simplement indéfinie. Aucune exception ne sera levée.

Cependant, vous ne pouvez pas référencer la variable déclarée avec let ou const tant qu'elle n'a pas été déclarée. Si vous essayez de l'utiliser avant sa déclaration, une exception sera générée lors de la phase d'exécution du contexte d'exécution. Maintenant, la variable sera toujours en mémoire, grâce à la phase de création du contexte d'exécution, mais le moteur ne vous permettra pas de l'utiliser:

function a(){
    b;
    let b;
}
a();
> Uncaught ReferenceError: b is not defined

Avec une variable définie avec var, si le moteur ne peut pas la trouver dans l'environnement variable du contexte d'exécution actuel, il remontera la chaîne de la portée (environnement externe) et vérifiera l'environnement variable de l'environnement extérieur pour la variable. S'il ne peut pas le trouver, il continuera à chercher dans la chaîne Scope. Ce n'est pas le cas avec let et const.

La deuxième caractéristique de let est-il introduit la portée du bloc. Les blocs sont définis par des accolades. Les exemples incluent les blocs fonction, if block, for block, etc. Lorsque vous déclarez une variable avec let inside, la variable est uniquement disponible à l'intérieur du bloc. En fait, chaque fois que le bloc est exécuté, par exemple dans une boucle for, il crée une nouvelle variable en mémoire.

ES6 introduit également le mot-clé const pour la déclaration de variables. const est également bloqué. La différence entre let et const réside dans le fait que les variables const doivent être déclarées à l'aide d'un initialiseur, sinon cela générera une erreur.

Enfin, en ce qui concerne le contexte d’exécution, les variables définies avec var seront attachées à l’objet 'this'. Dans le contexte d'exécution global, il s'agira de l'objet window dans les navigateurs. Ce n'est pas le cas pour let ou const.

0
Donato

Je pense que les termes et la plupart des exemples sont un peu accablants. Le problème principal que j’ai eu personnellement avec la différence est de comprendre ce qu’est un "blocage". À un moment donné, j’ai réalisé qu’un bloc serait constitué de toute accolade, à l’exception de la déclaration IF. un crochet ouvrant { d'une fonction ou d'une boucle définira un nouveau bloc; tout ce qui est défini avec let dedans ne sera pas disponible après le crochet fermant } de la même chose (fonction ou boucle); Dans cet esprit, il était plus facile de comprendre:

let msg = "Hello World";

function doWork() { // msg will be available since it was defined above this opening bracket!
  let friends = 0;
  console.log(msg);

  // with VAR though:
  for (var iCount2 = 0; iCount2 < 5; iCount2++) {} // iCount2 will be available after this closing bracket!
  console.log(iCount2);
  
    for (let iCount1 = 0; iCount1 < 5; iCount1++) {} // iCount1 will not be available behind this closing bracket, it will return undefined
  console.log(iCount1);
  
} // friends will no be available after this closing bracket!
doWork();
console.log(friends);
0
Dementic

Étant donné que j'essaie actuellement de comprendre en profondeur le langage JavaScript, je partagerai ma brève recherche, qui contient quelques-uns des excellents éléments déjà discutés, ainsi que d'autres détails dans une perspective différente.

Comprendre la différence entre var et let peut être plus facile si nous comprenons la différence entre fonction et block scope .

Considérons les cas suivants:

(function timer() {
    for(var i = 0; i <= 5; i++) {
        setTimeout(function notime() { console.log(i); }, i * 1000);
    }
})();


   Stack            VariableEnvironment //one VariablEnvironment for timer();
                                       // when the timer is out - the value will be the same value for each call
5. [setTimeout, i]  [i=5] 
4. [setTimeout, i]  
3. [setTimeout, i]
2. [setTimeout, i]
1. [setTimeout, i]
0. [setTimeout, i]

####################    

(function timer() {
    for (let i = 0; i <= 5; i++) {
        setTimeout(function notime() { console.log(i); }, i * 1000);
    }
})();

   Stack           LexicalEnvironment - each iteration has a new lexical environment
5. [setTimeout, i]  [i=5]       
                      LexicalEnvironment 
4. [setTimeout, i]    [i=4]     
                        LexicalEnvironment 
3. [setTimeout, i]      [i=3]       
                         LexicalEnvironment 
2. [setTimeout, i]       [i=2]
                           LexicalEnvironment 
1. [setTimeout, i]         [i=1]
                             LexicalEnvironment 
0. [setTimeout, i]           [i=0]

lorsque timer() est appelé, un ExecutionContext est créé et contient à la fois le VariableEnvironment et tous les LexicalEnvironments correspondant à chaque itération.

Et un exemple plus simple

Portée de la fonction

function test() {
    for(var z = 0; z < 69; z++) {
        //todo
    }
    //z is visible outside the loop
}

Portée du bloc

function test() {
    for(let z = 0; z < 69; z++) {
        //todo
    }
    //z is not defined :(
}
0
Lucian Nut