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


ECMAScript 6 introduit la let déclaration. Je l'ai entendu décrire comme une variable «locale», mais je ne suis toujours pas sûr de savoir comment il se comporte différemment de la var mot-clé.

Quelles sont les différences? Quand devrait let être utilisé sur var?


3238
2018-04-17 20:09


origine


Réponses:


La différence est la portée. var est portée au bloc de fonction le plus proche et let est portée à la plus proche enfermant block, qui peut être plus petit qu'un bloc fonctionnel. Les deux sont globaux si hors de tout bloc.

De plus, les variables déclarées avec let ne sont pas accessibles avant d'être déclarés dans leur bloc d'inclusion. Comme vu dans la démo, cela va lancer une exception ReferenceError.

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 de la sorte en dehors d'un bloc fonctionnel.

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

Cependant, les variables globales définies avec let ne sera pas ajouté en tant que propriétés sur le global window objet comme ceux définis avec var.

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

Fonction:

Ils sont identiques lorsqu'ils sont utilisés de la sorte dans un bloc fonction.

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

Bloc:

Voici la différence. let est seulement visible dans le for() boucle et var est visible à toute 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 un mode strict, var vous permettra de re-déclarer la même variable dans la même portée. D'autre part, let ne veut 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.

4549
2018-05-27 10:16



let peut également être utilisé pour éviter les problèmes avec les fermetures. Il lie la valeur fraîche plutôt que de conserver une ancienne référence comme indiqué dans les exemples ci-dessous.

DEMO

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. Référence à la i variable 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érera au même objet car il n'y a qu'un seul objet de compteur qui en contient 6, donc vous en obtenez six à chaque clic.

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

DEMO (Testé dans Chrome et Firefox 50)

'use strict';

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

450
2018-04-17 20:11



Voici un explication de la let mot-clé avec quelques exemples.

laissez travailler beaucoup comme var. La principale différence est que la portée d'une variable var est la totalité de la fonction englobante

Cette table sur Wikipedia montre quels navigateurs supportent 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.


129
2018-02-23 18:35



Quelle est la différence entre let et var?

  • Une variable définie à l'aide d'un var déclaration est connue tout au long la fonction il est défini dans, depuis le début de la fonction. (*)
  • Une variable définie à l'aide d'un let déclaration est seulement connue dans le bloc elle est définie à partir du moment où elle est définie. (**)

Pour comprendre la différence, considérez 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 est seulement connu dans la première boucle, mais pas avant et après. Pourtant, notre variable i est connu dans toute la fonction.

En outre, considérez que les variables de portée de bloc ne sont pas connues avant d'être déclarées car elles ne sont pas levées. Vous n'êtes également pas autorisé à redéclarer la même variable étendue 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 hissées et qui ne produisent pas d'erreurs dans le cas de déclarations multiples.


Est-il sécuritaire d'utiliser let aujourd'hui?

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

Aujourd'hui, cependant, ce n'est certainement pas le cas. En fait, nous devons nous demander si l'utilisation du let déclaration. La réponse à cette question dépend de votre environnement:

  • Si vous écrivez du code JavaScript côté serveur (Node.js), vous pouvez utiliser le let déclaration.

  • Si vous écrivez du code JavaScript côté client et utilisez un transpiler (comme Traceur), vous pouvez utiliser le let déclaration, cependant votre code est susceptible d'être tout sauf optimal en ce qui concerne la performance.

  • Si vous écrivez du code JavaScript côté client et n'utilisez pas de transpiler, vous devez prendre en compte le support du navigateur.

Aujourd'hui, 8 juin 2018, il y a 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 supportant le let déclaration au moment de votre lecture de cette réponse, voir ce Can I Use page.


(*) Les variables globales et fonctionnelles peuvent être initialisées et utilisées avant d'être déclarées car les variables JavaScript sont hissé. Cela signifie que les déclarations sont toujours très en haut de la portée.

(**) Les variables de portée de bloc ne sont pas hissées


115
2018-06-02 20:59



La réponse acceptée manque un point:

{
  let a = 123;
};

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

98
2018-04-17 21:38



Il y a quelques différences subtiles - let La portée se comporte davantage comme une portée variable dans plus ou moins d'autres langues.

par exemple. Il s'étend au bloc qui l'entoure, Ils n'existent pas avant d'être déclarés, etc.

Cependant, il vaut la peine de noter que let est seulement une partie des implémentations Javascript plus récentes et a différents degrés de support du navigateur.


40
2018-03-06 10:41



Voici un exemple de différence entre les deux (le support vient de démarrer pour chrome): enter image description here

Comme vous pouvez le voir var j variable a toujours une valeur en dehors de la portée de la boucle for (bloc Scope), mais let i La variable est indéfinie en dehors de la portée 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);


39
2017-11-23 22:52



let

Bloquer la portée

Variables déclarées en utilisant le let mot-clé sont de portée bloc, ce qui signifie qu'ils ne sont disponibles que dans le bloc dans lequel ils ont été déclarés.

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

Au niveau supérieur, les variables déclarées en utilisant let ne crée 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

Dans 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

Dans un bloc

Variables déclarées en utilisant let à l'intérieur d'un bloc ne peut pas être accédé 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

Variables déclarées avec let Les boucles in peuvent être référencées uniquement dans 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 fermetures

Si tu utilises let au lieu de var dans une boucle, à chaque itération vous obtenez une nouvelle variable. Cela signifie que vous pouvez utiliser en toute sécurité une fermeture à l'intérieur d'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 temporale

En raison de la zone morte temporelle, variables déclarées en utilisant let ne peut pas être consulté avant d'être déclaré. Tenter de le faire provoque 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 en utilisant let. Vous ne pouvez pas non plus déclarer une variable en utilisant let avec le même identifiant qu'une autre variable qui a été déclaré en utilisant 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 est bloc-portée et a TDZ. Il y a cependant deux choses qui sont différentes.

Pas de réaffectation

Variable déclarée en utilisant const ne peut pas être réaffecté.

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'initialisateur est requis

Vous devez toujours spécifier une valeur lors de la déclaration d'une variable en utilisant const.

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

37
2018-01-17 15:11



  • Variable ne pas lever

    let volonté pas hisser à l'ensemble de la portée du bloc, ils apparaissent. En revanche, var pourrait hisser 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, Tous les deux var et let sont hissés.

  • Collecte des ordures

    Bloquer la portée de let est utile concerne les fermetures et la collecte des ordures pour 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 click rappel de gestionnaire n'a pas besoin de la hugeData variable du tout. Théoriquement, après process(..) s'exécute, l'énorme structure de données hugeData pourrait être ramassé. Cependant, il est possible que certains moteurs JS doivent encore garder cette structure énorme, puisque le click fonction a une fermeture sur l'ensemble de la portée.

    Cependant, la portée du bloc peut faire de cette énorme structure de données une poubelle collectée.

    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 re-lie à chaque itération de la boucle, en veillant à lui attribuer la valeur 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 avec let

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

    Car let créer un nouvel environnement lexical avec ces noms pour a) l'expression initialiser b) chaque itération (avant l'évaluation de l'expression d'incrément), plus de détails sont ici.


20
2018-03-22 14:39