Question

ECMAScript 6 introduit l'instruction let .

Je l'ai entendu qu'il est décrit comme une variable « locale », mais je ne suis toujours pas tout à fait sûr de savoir comment il se comporte différemment que le mot-clé var.

Quelles sont les différences? Quand faut-il let être utilisé sur var?

Était-ce utile?

La solution

règles de scoping

La principale différence est règles de portée. Les variables déclarées par mot-clé var est scope sur le corps de fonction immédiate (d'où le champ d'application de la fonction), tandis que les variables de let sont étendus à l'immédiat enfermant bloc indiqué par { } (d'où le champ de bloc).

function run() {
  var foo = "Foo";
  let bar = "Bar";

  console.log(foo, bar);

  {
    let baz = "Bazz";
    console.log(baz);
  }

  console.log(baz); // ReferenceError
}

run();

La raison pour laquelle mot-clé let a été introduit dans la langue était la portée de la fonction est source de confusion et a été l'une des principales sources de bogue dans javascript.

Jetez un oeil à cet exemple de une autre question stackoverflow :

var funcs = [];
// let's create 3 functions
for (var i = 0; i < 3; i++) {
  // and store them in funcs
  funcs[i] = function() {
    // each should log its value.
    console.log("My value: " + i);
  };
}
for (var j = 0; j < 3; j++) {
  // and now let's run each one to see
  funcs[j]();
}

My value: 3 était sortie à la console chaque funcs[j](); de temps a été invoqué depuis des fonctions anonymes étaient liées à la même même variable.

Les gens devaient créer immédiatement créer des fonctions invoquées pour capturer la valeur correcte des boucles, mais qui était aussi poilu.

Hisser

Alors que les variables déclarées avec mot-clé var sont « hissés » au sommet du bloc qui signifie qu'ils sont accessibles dans leur portée englobante avant même qu'ils sont déclarés:

function run() {
  console.log(foo); // undefined
  var foo = "Foo";
  console.log(foo); // Foo
}

run();

let variables ne sont pas initialisés jusqu'à ce que leur définition est évaluée. Accès à eux avant que les résultats d'initialisation dans un ReferenceError. Ladite variable d'être en « zone morte temporelle » dès le début du bloc jusqu'à ce que l'initialisation est traitée.

function checkHoisting() {
  console.log(foo); // ReferenceError
  let foo = "Foo";
  console.log(foo); // Foo
}

checkHoisting();

Création propriété globale de l'objet

Au niveau supérieur, let, à la différence var, ne crée pas une propriété sur l'objet global:

var foo = "Foo";  // globally scoped
let bar = "Bar"; // globally scoped

console.log(window.foo); // Foo
console.log(window.bar); // undefined

Redéclaration

En mode strict, var vous permettra de re-déclarer la même variable dans la même portée en let soulève une SyntaxError.

'use strict';
var foo = "foo1';
var foo = "foo2'; // No problem, 'foo' is replaced.

let bar = "bar1";
let bar = "bar2"; // SyntaxError: Identifier 'bar' has already been declared

Autres conseils

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

for(var i=1; i<6; i++) {
  $("#div" + i).click(function () { console.log(i); });
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="div1">1</div>
<div id="div2">2</div>
<div id="div3">3</div>
<div id="div4">4</div>
<div id="div5">5</div>

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

Chaque gestionnaire de clic référence au même objet, car il n'y a qu'un seul objet de compteur qui détient 6 ainsi vous obtenez six sur chaque clic.

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

(testé en chrome et Firefox 50)

for(let i=1; i<6; i++) {
  $("#div" + i).click(function () { console.log(i); });
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="div1">1</div>
<div id="div2">2</div>
<div id="div3">3</div>
<div id="div4">4</div>
<div id="div5">5</div>

Quelle est la différence entre let et var?

  • Une variable définie en utilisant une instruction var est connue à travers la fonction il est défini dans, dès le début de la fonction. *
  • Une variable définie en utilisant une instruction let est seulement connu dans < strong> bloc il est défini dans, à partir du moment où il est défini en avant. **

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 j variable est seulement connue dans la première boucle, mais pas avant et après. Pourtant, notre i variable est connue dans toute la fonction.

En outre, considèrent que les variables scope de bloc ne sont pas connus avant qu'ils ne soient déclarés parce qu'ils ne sont pas hissés. Vous êtes également pas autorisé à redéclarer le même bloc scope variable dans le même bloc. Cela rend les variables scope bloc moins sujette aux erreurs que globalement ou les variables fonctionnellement scope, qui sont hissés et qui ne produisent pas d'erreur en cas de multiples déclarations.


Est-il sûr d'utiliser let aujourd'hui?

Certains prétendent que, dans l'avenir, nous allons utiliser des déclarations et laisser seulement que les déclarations var deviendront caduques. JavaScript gourou Kyle Simpson écrit un article très élaboré pourquoi il croit que ne sera pas le cas .

Aujourd'hui, cependant, qui est certainement pas le cas. En fait, nous avons vraiment besoin de se demander s'il est sûr d'utiliser l'instruction de 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 et utiliser un transpiler basé sur un navigateur (comme côté client < strong> Traceur ou babel-autonome ), vous pouvez utiliser en toute sécurité la déclaration de let, mais votre code est susceptible d'être autre chose que optimale par rapport à la performance.

  • Si vous écrivez du code JavaScript côté client et utiliser un transpiler à base de nœud (comme le script shell traceur ou Babel ), vous pouvez utiliser en toute sécurité la déclaration de let. Et parce que votre navigateur ne reconnaîtra le code transpiled, les inconvénients de performance devraient être limitées.

  • Si vous écrivez du code JavaScript côté client et ne pas utiliser un transpiler, vous devez envisager un soutien du navigateur.

    Il y a encore certains navigateurs qui ne prennent pas en charge let du tout:

 Table de support


Comment garder une trace de l'aide du navigateur

Pour un aperçu des navigateurs prennent en charge l'instruction let mise à jour au moment de votre lecture de cette réponse, voir hissés . Cela signifie que les déclarations sont toujours bien au-dessus de la portée.

** variables de bloc scope ne sont pas hissés

Voici un du mot-clé let avec quelques exemples.

  

let fonctionne comme var. La principale différence est que la portée d'une variable de var est la fonction entière d'enceinte

Ce tableau sur Wikipédia montre que les navigateurs en charge JavaScript 1.7.

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

La réponse acceptée manque un point:

{
  let a = 123;
};

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

let

Portée des

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

Au niveau supérieur (à l'extérieur d'une fonction)

Au niveau supérieur, les variables déclarées à l'aide 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

intérieur d'une fonction

A l'intérieur d'une fonction (mais à l'extérieur 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 let dans un bloc ne sont pas accessibles 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

intérieur d'une boucle

Les variables déclarées avec let dans les boucles peuvent être référencées seulement 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 vous utilisez 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 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);
}

Temporal zone morte

En raison de zone morte temporelle, les variables déclarées à l'aide let ne peut pas être accessible avant qu'ils ne soient déclarés. Toute tentative 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 changement de déclarer

Vous ne pouvez pas déclarer la même variable plusieurs fois à l'aide let. Vous pouvez également ne pas déclarer une variable en utilisant let avec le même identifiant comme une autre variable qui a été déclarée à l'aide 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 tout à fait semblable à let-il est bloc-scope et a TDZ. Il y a, cependant, deux choses qui sont différentes.

Aucun réattribuant

Variable déclaré à l'aide const ne peut ê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és.

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

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

Initializer est nécessaire

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

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

Voici un exemple de la différence entre les deux (support juste commencé pour le chrome):
entrer image description ici

Comme vous pouvez le voir la variable var j est d'avoir encore une valeur en dehors de la portée de la boucle (Portée bloc), mais la variable let i n'est pas défini en dehors du champ d'application pour la boucle.

"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);

Il y a quelques différences subtiles - détermination de la portée de let se comporte plus comme la portée des variables fait dans plus ou moins toutes les autres langues.

par exemple. Il étendues au bloc englobante, ils n'existent pas avant qu'ils ne soient déclarés, etc.

Cependant, il convient de noter que let est une partie seulement de nouvelles implémentations Javascript et a des degrés divers de soutien du navigateur .

  • Variable Non Levage

    let sera hissez pas pour l'ensemble du périmètre du bloc apparaissent dans. 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, par @Bergi, deux var et let sont hissés .

  • Garbage Collection

    Bloc portée de let est utile concerne des fermetures et la collecte des déchets pour récupérer la mémoire. Considérons,

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

    Le rappel du gestionnaire de click n'a pas besoin de la variable hugeData du tout. En théorie, après l'exécution de process(..), l'énorme structure de données hugeData pourrait être garbage collection. Cependant, il est possible que certains moteurs JS aura toujours garder cette énorme structure, la fonction de click a une fermeture sur l'ensemble du périmètre.

    Cependant, la portée de bloc peut faire de cette énorme structure de données pour les déchets collectés.

    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){
        //....
    });
    
  • boucles let

    let dans la boucle peut re-lie it pour chaque itération de la boucle, en veillant à ré-assigner la valeur à partir de la fin de l'itération de la boucle précédente. Considérons,

    // 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);  
    }
    

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

La principale différence est le champ différence, alors que laisser peut être uniquement disponible à l'intérieur du champ il est déclaré, comme dans la boucle for, < strong> var est accessible en dehors de la boucle par exemple. De la documentation (exemples MDN aussi de MDN):

  

laissez vous permet de déclarer des variables qui sont limitées portée au bloc, déclaration, ou une expression sur laquelle il est utilisé. Ce qui est différent du var mot-clé, qui définit une variable globalement ou localement à une fonction entière indépendamment de la portée du bloc.

     

Les variables déclarées par let dans leur champ le bloc dans lequel elles sont définies, ainsi que dans tous les contenus sous-blocs. De cette façon, laisser fonctionne comme var . La principale différence est que la portée d'une variable var est la fonction entière englobant:

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 fonctions, let , contrairement à var , ne crée pas une 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é dans un bloc, laissez limite 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

Aussi, ne pas oublier qu'il est caractéristique ECMA6, il est donc pas encore totalement pris en charge, il est donc préférable transpiles toujours à l'aide de Babel ECMA5 etc ... Pour plus d'informations sur la visite site babel

Voici un exemple pour ajouter à ce que les autres ont déjà écrit. Supposons que vous voulez faire un éventail de fonctions, adderFunctions, où chaque fonction prend un seul argument Number et renvoie la somme de l'argument et l'indice de la fonction dans le tableau. Essayer de générer adderFunctions avec une boucle en utilisant le mot-clé var ne fonctionnera pas la façon dont une personne peut attendre ingénument:

// 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 procédé ci-dessus ne génère pas de la matrice désirée de fonctions, car la portée de i prolonge 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, le i dans la fermeture de chaque fonction se réfère à la valeur de i à la fin de la boucle (1000) pour chaque fonction anonyme en adderFunctions. Ce n'est pas ce que nous voulions du tout: nous avons maintenant un tableau de 1000 fonctions différentes dans la mémoire avec exactement le même comportement. Et si nous mettons à jour par la suite la valeur de i, la mutation aura une incidence sur tous les adderFunctions.

Cependant, nous pouvons essayer d'utiliser à nouveau 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-ci, est i rebond à chaque itération de la boucle de for. Chaque fonction conserve maintenant la valeur de i au moment de la création de la fonction, et adderFunctions se comporte comme prévu.

Maintenant, l'image de mélanger les deux comportements et vous verrez probablement pourquoi il est recommandé de ne pas mélanger les plus récents let et const avec le var plus dans le même script. Cela peut entraîner un peu de code spectaculairement confusion.

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 arrive. Utilisez un linter.

  

Remarque: Ceci est un exemple d'enseignement destiné à démontrer le comportement var / let dans les boucles et les fermetures de fonctions qui seraient également faciles à comprendre. Ce serait une façon terrible pour ajouter des numéros. Mais la technique générale de la saisie des données dans les fermetures de fonctions anonymes peut se rencontrer dans le monde réel dans d'autres contextes. YMMV.

La différence est dans le champ d'application de des variables déclarées avec chacun.

Dans la pratique, il y a un certain nombre de conséquences utiles de la différence de portée:

  1. variables let ne sont visibles que dans leur englobante le plus proche bloc ({ ... }).
  2. variables let ne sont utilisables que dans les lignes de code qui se produisent après la variable est déclarée (même si ils sont hissés !).
  3. variables let ne peuvent pas être redéclarées par une var ultérieure ou let.
  4. Les variables globales de let ne sont pas ajoutés à l'objet global window.
  5. variables let sont facile à utiliser avec des fermetures (ils ne causent pas conditions de course ).

Les restrictions imposées par let réduisent la visibilité des variables et augmentent la probabilité que les collisions de noms inattendus se trouvent au début. Cela rend plus facile de suivre et de la raison sur les variables, y compris leur joignabilité (aidant à récupérer la mémoire inutilisée) .

Par conséquent, les variables let sont moins susceptibles de causer des problèmes lorsqu'ils sont utilisés dans les grands programmes ou lorsque des cadres indépendamment développés sont combinés dans des façons nouvelles et inattendues.

var peut encore être utile si vous êtes sûr que vous voulez que l'effet unique contraignant lors de l'utilisation d'une fermeture dans une boucle (# 5) ou pour déclarer des variables globales extérieurement visibles dans votre code (# 4). L'utilisation de var pour les exportations peut être supplanté si export émigre d'espace transpiler et dans la langue de base.

Exemples

1. Ne pas utiliser le bloc englobante la plus proche à l'extérieur: Ce bloc de code renvoient une erreur de référence parce que la deuxième utilisation de x se produit en dehors du bloc où elle est déclarée avec let:

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

En revanche, le même exemple avec des œuvres de var.

2. Ne pas utiliser avant la déclaration: Ce bloc de code va lancer une ReferenceError avant que le code peut être exécuté, car x est utilisé avant qu'il ne soit déclaré:

{
    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 analyse et exécute var sans lancer aucune exception.

3. Non redéclaration: Le code suivant montre qu'une variable déclarée avec let ne peut pas être redéclaré plus tard:

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

4. Globals pas 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. Facile à utiliser avec des fermetures: Les variables déclarées avec var ne fonctionnent pas bien avec des fermetures à l'intérieur des boucles. Voici une simple boucle qui délivre en sortie la séquence de valeurs que la variable a i à différents points dans le temps:

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

Plus précisément, cette commande affiche:

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

En JavaScript, nous utilisons souvent des variables à un moment beaucoup plus tard que lors de leur création. Lorsque nous démontrons en retardant la sortie d'une fermeture est passé à setTimeout:

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

... la sortie reste inchangée tant que nous restons fidèles à let. En revanche, si nous avions utilisé à la place var i:

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

... la boucle émet de façon inattendue "i est 5" cinq fois:

i is 5
i is 5
i is 5
i is 5
i is 5

Que les deux fonctions suivantes montrent 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
}

let est intéressant, car il 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 se traduit par comptage [0, 7].

Alors

(() => {
    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++);
            }
        }
    }
})();

Seuls les chefs d'accusation [0, 1].

Fonction VS portée de bloc:

La principale différence entre var et let est que les variables déclarées avec var sont fonction scope . Alors que les fonctions déclarées avec let sont bloc scope . 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, a déclaré à var, est toujours accessible en dehors du compte de if. Cette foo variable serait disponible partout dans le cadre de la testVar Fonction .

variables avec let:

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

variables let ne sont pas hissés:

Une autre différence entre var et let est avec des variables déclarées avec let ne pas se hisse . Un exemple est la meilleure façon d'illustrer ce comportement:

variables avec let ne pas se hisse:

console.log(letVar);

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

variables avec var faire se hisse:

console.log(varVar);

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

let Global ne soit pas attaché à window:

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

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

  

Quand faut-let être utilisé sur var?

Utilisez let sur var chaque fois que vous pouvez simplement parce qu'il est scope plus spécifique. Cela réduit les conflits de noms potentiels qui peuvent survenir lorsque un grand nombre de variables. var peut être utilisé lorsque vous souhaitez une variable globale explicitement d'être sur l'objet window (tenez toujours compte si cela est vraiment nécessaire).

Il apparaît également que, au moins dans Visual Studio 2015, tapuscrit 1.5, « var » permet à plusieurs déclarations du même nom de variable dans un bloc, et « laisser » ne fonctionne pas.

Cela ne génère pas une erreur de compilation:

var x = 1;
var x = 2;

Cette volonté:

let x = 1;
let x = 2;

var est variable portée globale (palan-mesure).

let et const est bloquer la portée.

  

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

lors de l'utilisation let

Le mot-clé let attache la déclaration variable à la portée de tout le bloc (généralement une paire de { .. }) il est contenu dans. En d'autres termes, let détourne implicitement la portée de sa déclaration variable tout bloc.

variables let ne peuvent pas accéder à l'objet window parce qu'ils ne sont pas accessibles à l'échelle mondiale.

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 var

var et variables ES5 des fonctions étendues n'a sens les variables sont valables dans la fonction et non en dehors de la fonction elle-même.

variables var sont accessibles dans l'objet window parce qu'ils ne sont pas accessibles à l'échelle mondiale.

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

Si vous voulez en savoir plus continuer à lire ci-dessous

l'une des questions d'entrevue les plus célèbres sur la portée peut également suffire l'utilisation exacte de let et var comme ci-dessous;

Lorsque 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, lors de l'utilisation let, pour chaque itération de boucle est la variable scope et a sa propre copie.

Lorsque vous utilisez var

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

En effet, lors de l'utilisation var, pour chaque itération de boucle la variable est une copie scope et a partagé.

Si je lis les spécifications à droite, puis let heureusement peut également être mis à profit pour éviter fonctions d'auto-Invocation utilisées pour simuler les membres seulement privés - un modèle de conception populaire qui diminue la lisibilité du code, complique le débogage, qui ajoute pas réel code de protection ou d'autres avantages - sauf peut-être satisfaire le désir de quelqu'un pour la sémantique, donc cesser de l'utiliser. / Diatribe

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 « interfaces privées Emulation

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)

let vs var. Il est tout au sujet de champ .

les variables var sont globales et sont accessibles pratiquement partout, tandis que laisser les variables ne sont pas globaux et jusqu'à ce qu'une existent seulement parenthèse fermante les tue.

Voir mon exemple ci-dessous, et notez comment le lion (LET) variable agit différemment dans les deux console.logs; il devient hors de portée dans la 2ème 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.

let est une partie de ES6. Ces fonctions expliquent 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
}

Auparavant, il n'y avait que deux champs d'application en JavaScript, à savoir fonctionnel et mondial. Avec mot-clé 'let' JavaScript a introduit des variables block-level.

Pour avoir une compréhension complète du mot-clé 'let', ES6: « let » mot-clé à déclarer variable JavaScript help

.

Maintenant, je pense qu'il est mieux portée des variables à un bloc d'instructions en 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 laisser ici après tant qu'ils auront portée similaire en JavaScript comme d'autres langues, Java, C #, etc.

Les personnes ayant pas une compréhension claire de la portée en JavaScript utilisés pour l'erreur plus tôt.

est Hisser pas pris en charge en utilisant let.

Avec cette erreur d'approche actuelles OBTIENNENT enlevés en JavaScript.

Reportez-vous à ES6 En profondeur :. const et laissez pour comprendre mieux

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

  

const est un signal que l'identifiant ne soit pas réaffecté.

     

let, est un signal qui peut être réaffecté la variable, tel 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, il est défini dans,   qui est pas toujours la totalité de la fonction contenant.

     

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

https: // support. com / javascript scène / javascript-ES6-var-let-ou-const-ba58b8dcde75 # .esmkpbg9b

Comme mentionné ci-dessus:

  

La différence est la portée. var est scope au plus proche fonction   bloc et let est portée définie à la bloc englobant la plus proche   peut être plus petit qu'un bloc de fonction. Les deux sont en dehors de toute mondiale si   block.Lets voir un exemple:

Example1:

Dans mes deux exemples que j'ai une myfunc fonction. myfunc contient une myvar variable est égale à 10. Dans mon premier exemple que je vérifie si myvar est égal à 10 (myvar==10). Si oui, je déclare planifions une myvar variable (maintenant j'ai deux variables myvar) en utilisant le mot de var et lui attribuer une nouvelle valeur (20). Dans la ligne suivante, j'imprime sa valeur sur ma console. Une fois le bloc conditionnel imprimer à nouveau la valeur de myvar sur ma console. Si vous regardez la sortie de myfunc, myvar a une valeur égale à 20.

Example2: Dans mon deuxième exemple au lieu d'utiliser de mot-clé var dans mon bloc conditionnel Je déclare myvar en utilisant le mot de let. Maintenant, quand je l'appelle myfunc je reçois deux sorties différentes: myvar=20 et myvar=10

.

Donc, la différence est très simple i.e. son champ d'application.

Jetez un oeil à cette image, j'ai créé un exemple très simple pour la démonstration de variables const et let. Comme vous pouvez le voir, lorsque vous essayez de changer variable const, vous obtiendrez l'erreur ( Tentative de remplacer « nom » qui est constant '), mais jetez un oeil à variable let ...

D'abord, nous déclarons let age = 33, et plus tard attribuons une autre valeur age = 34;, qui est ok, nous ne disposons pas d'erreurs quand nous essayons de changer la variable let

Je pense que les termes et la plupart des exemples sont un peu écrasante, La question principale que j'ai eu personnellement la différence est de comprendre ce qu'est un « bloc » est. À un certain moment j'ai réalisé, un bloc serait des accolades à l'exception de la déclaration de IF. un support d'ouverture { d'une fonction ou d'une boucle définit un nouveau bloc, tout défini par let à l'intérieur, ne sera pas disponible après le crochet de fermeture } de la même chose (fonction ou boucle); Dans cet esprit, il était plus facile à 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);

Comme je suis en train d'essayer d'obtenir une compréhension approfondie de JavaScript Je vais partager ma brève recherche qui contient quelques-uns des grands morceaux déjà abordés ainsi que quelques 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 Bloc champ .

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]

quand timer() est appelé ExecutionContext est créé qui contiendra à la fois VariableEnvironment et tous les LexicalEnvironments correspondant à chaque itération.

Et un exemple plus simple

Portée Fonction

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

Portée de bloc

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

Je veux relier ces mots-clés au contexte d'exécution, parce que le contexte d'exécution est important dans tout cela. Le contexte d'exécution comporte deux phases: une phase de création et de la phase d'exécution. De plus, chaque contexte d'exécution a une variable d'environnement et de l'environnement extérieur (son environnement lexicales).

Au cours de la phase de création d'un contexte d'exécution, var, laissez et CONST encore stocker sa variable en mémoire avec une valeur indéfinie dans l'environnement variable du contexte d'exécution donnée. La différence est dans la phase d'exécution. Si vous utilisez une référence variable définie par var avant qu'elle ne se voit attribuer une valeur, il sera juste indéfini. Aucune exception ne sera soulevée.

Cependant, vous ne pouvez pas faire référence à la variable déclarée avec let ou const jusqu'à ce qu'il soit déclaré. Si vous essayez de l'utiliser avant qu'il ne soit déclaré, une exception sera soulevée au cours de la phase d'exécution du contexte d'exécution. Maintenant, la variable sera toujours en mémoire, avec la permission de la phase de création du contexte d'exécution, mais le moteur ne permet pas de l'utiliser:

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

Avec une variable définie par var, si le moteur ne peut pas trouver la variable dans le courant de l'environnement variable de contexte d'exécution, il va monter la chaîne de portée (l'environnement extérieur) et vérifier l'environnement variable de l'environnement extérieur pour la variable. Si elle ne peut pas le trouver là, elle continuera de chercher 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 des blocs fonctionnels, si des blocs, des blocs, etc. Lorsque vous déclarez une variable à l'intérieur let d'un bloc, 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, il va créer une nouvelle variable dans la mémoire.

ES6 introduit également le mot-clé const pour déclarer des variables. const est également bloquer scope. La différence entre let et const est que les variables const doivent être déclarées au moyen d'un initialiseur, ou il va générer une erreur.

Et enfin, en ce qui concerne le contexte d'exécution, les variables définies par var seront attachés au « ce » objet. Dans le contexte global d'exécution, qui sera l'objet de la fenêtre dans les navigateurs. Ce n'est pas le cas pour let ou const.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top