Quelle est la différence entre utiliser «let» et «var»?

4545

ECMAScript 6 présente la letdéclaration .

Je l'ai entendu dire qu'elle est décrite comme une variable "locale", mais je ne sais toujours pas comment elle se comporte différemment du varmot clé.

Quelles sont les différences? Quand faut- letil l'utiliser var?

TM.
la source
105
ECMAScript est la norme et letest inclus dans le projet de 6e édition et sera très probablement dans la spécification finale.
Richard Ayotte
5
Voir kangax.github.io/es5-compat-table/es6 pour une matrice de prise en charge à jour des fonctionnalités ES6 (y compris let). Au moment de la rédaction de Firefox, Chrome et IE11 le prennent tous en charge (bien que je pense que la mise en œuvre de FF ne soit pas tout à fait standard).
Nico Burns
22
Pendant longtemps, je ne savais pas que les vars dans une boucle for étaient limités à la fonction dans laquelle elle était enveloppée. Je me souviens avoir compris cela pour la première fois et j'ai pensé que c'était très stupide. Je vois un certain pouvoir, bien que je sache maintenant comment les deux pourraient être utilisés pour des raisons différentes et comment, dans certains cas, vous voudrez peut-être utiliser un var dans une boucle for et ne pas le définir dans le bloc.
Eric Bishard
1
Ceci est une très bonne lecture wesbos.com/javascript-scoping
onmyway133
1
Réponse bien expliquée ici stackoverflow.com/a/43994458/5043867
Pardeep Jain

Réponses:

6102

Règles de cadrage

La principale différence réside dans les règles de portée. Les variables déclarées par varmot-clé sont étendues au corps de fonction immédiat (d'où la portée de la fonction) tandis que les letvariables sont étendues au bloc englobant immédiat désigné par { }(d'où la portée du 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 le letmot clé a été introduit dans le langage était la portée de la fonction est déroutante et était l'une des principales sources de bogues dans JavaScript.

Jetez un œil à cet exemple d' une autre question de 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: 3a été sortie sur la console à chaque fois funcs[j]();que des fonctions anonymes étaient liées à la même variable.

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

Levage

Alors que les variables déclarées avec le varmot clé sont hissées (initialisées avec undefinedavant l'exécution du code), ce qui signifie qu'elles sont accessibles dans leur portée englobante avant même qu'elles ne soient déclarées:

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

run();

letles variables ne sont initialisées qu'après évaluation de leur définition. Leur accès avant l'initialisation se traduit par a ReferenceError. Variable dite "en zone morte temporelle" depuis le début du bloc jusqu'à ce que l'initialisation soit traitée.

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

checkHoisting();

Création d'une propriété d'objet globale

Au niveau supérieur let, contrairement à var, ne crée pas de 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, varvous permettra de re-déclarer la même variable dans la même portée tout en letlançant 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
ThinkingStiff
la source
23
N'oubliez pas que vous pouvez créer un bloc à tout moment. function () {code; {let inBlock = 5; } code; };
moyenne Joe
177
Le but des instructions let est-il donc uniquement de libérer de la mémoire lorsqu'elles ne sont pas nécessaires dans un certain bloc?
NoBugs
219
@NoBugs, oui, et il est encouragé que les variables n'existent que là où elles sont nécessaires.
batman
67
letl'expression de bloc let (variable declaration) statementn'est pas standard et sera supprimée à l'avenir, bugzilla.mozilla.org/show_bug.cgi?id=1023609 .
Gajus
19
Donc, je ne peux penser à aucun cas où l'utilisation de var est utile. Quelqu'un pourrait-il me donner un exemple d'une situation où il est préférable d'utiliser var?
Luis Sieira
622

letpeut é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.

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>
<p>Clicking on each number will log to console:</p> 
<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>

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

Chaque gestionnaire de clic unique fera référence au même objet car il n'y a qu'un seul objet compteur qui en contient 6, vous en obtenez donc six à chaque clic.

Une solution de contournement générale consiste à envelopper cela dans une fonction anonyme et à passer icomme argument. De tels problèmes peuvent également être évités maintenant en utilisant à la letplace varcomme indiqué dans le code ci-dessous.

(Testé dans 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>
<p>Clicking on each number will log to console:</p> 
<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>

Gurpreet Singh
la source
54
C'est vraiment cool. Je m'attendrais à ce que "i" soit défini en dehors du corps de la boucle contient entre crochets et ne forme PAS une "fermeture" autour de "i". Bien sûr, votre exemple prouve le contraire. Je pense que c'est un peu déroutant du point de vue de la syntaxe, mais ce scénario est si courant qu'il est logique de le prendre en charge de cette manière. Merci beaucoup d'avoir soulevé cette question.
Karol Kolenda
9
IE 11 prend en charge let, mais il alerte "6" pour tous les boutons. Avez-vous une source indiquant comment letdevrait se comporter?
Jim Hunziker du
10
On dirait que votre réponse est le comportement correct: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Jim Hunziker
11
En effet, c'est un piège courant dans Javascript et maintenant je peux voir pourquoi letserait vraiment utile. La définition d'écouteurs d'événements dans une boucle ne nécessite plus d'expression de fonction immédiatement invoquée pour la portée locale ià chaque itération.
Adrian Moisa
19
L'utilisation de "let" ne fait que différer ce problème. Ainsi, chaque itération crée une portée de bloc indépendante privée, mais la variable "i" peut toujours être corrompue par des modifications ultérieures au sein du bloc, (étant donné que la variable d'itérateur n'est généralement pas modifiée dans le bloc, mais d'autres variables let déclarées dans le bloc peuvent bien être) et toute fonction déclarée dans la boîte de bloc, lorsqu'il est invoqué, corrompre la valeur de « i » pour d' autres fonctions déclarées dans le bloc , car ils font part du même bloc privé donc la même référence à « i ».
Gary
199

Quelle est la différence entre letet var?

  • Une variable définie à l'aide d'une varinstruction est connue dans toute la fonction dans laquelle elle est définie, depuis le début de la fonction. (*)
  • Une variable définie à l'aide d'une letinstruction n'est connue que dans le bloc dans lequel 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 jn'est connue que dans la première boucle for, mais pas avant ni après. Pourtant, notre variable iest connue dans toute la fonction.

Tenez également compte du fait que les variables de portée de bloc ne sont pas connues avant d'être déclarées car elles ne sont pas hissées. Vous n'êtes pas non plus autorisé à redéclarer la même variable de portée de bloc dans le même bloc. Cela rend les variables de portée de bloc moins sujettes aux erreurs que les variables de portée globale ou fonctionnelle, qui sont hissées et qui ne produisent aucune erreur en cas de déclarations multiples.


Est-il sûr d'utiliser letaujourd'hui?

Certaines personnes diront qu'à l'avenir, nous n'utiliserons que les instructions let et que les instructions var deviendront obsolètes. Le gourou de JavaScript Kyle Simpson a écrit un article très élaboré sur les raisons pour lesquelles il pense que ce ne sera pas le cas .

Aujourd'hui, cependant, ce n'est certainement pas le cas. En fait, nous devons réellement nous demander s'il est sûr d'utiliser la letdé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 l' letinstruction en toute sécurité .

  • Si vous écrivez du code JavaScript côté client et utilisez un transpilateur basé sur un navigateur (comme Traceur ou babel-standalone ), vous pouvez utiliser en toute sécurité l' letinstruction, cependant votre code est susceptible d'être tout sauf optimal en termes de performances.

  • Si vous écrivez du code JavaScript côté client et utilisez un transpilateur basé sur Node (comme le script shell traceur ou Babel ), vous pouvez utiliser l' letinstruction en toute sécurité . Et comme votre navigateur ne connaîtra que le code transpilé, les inconvénients de performances devraient être limités.

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

    Il existe encore des navigateurs qui ne prennent pas letdu tout en charge:

entrez la description de l'image ici


Comment suivre la prise en charge du navigateur

Pour une vue d'ensemble à jour des navigateurs qui prennent en charge la letdéclaration au moment de la lecture de cette réponse, consultez cette Can I Usepage .


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

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

John Slegers
la source
14
concernant la réponse v4: iEST connue partout dans le bloc fonctionnel! Il commence par undefined(en raison du levage) jusqu'à ce que vous affectiez une valeur! ps: letest également hissé (en haut de son bloc contenant), mais donnera un ReferenceErrorlorsqu'il est référencé dans le bloc avant la première affectation. (PS2: Je suis un gars pro-point-virgule, mais vous n'avez vraiment pas besoin d'un point-virgule après un bloc). Cela dit, merci d'avoir ajouté la vérification de la réalité concernant le support!
GitaarLAB
@GitaarLAB: Selon le Mozilla Developer Network : "Dans ECMAScript 2015, les liaisons let ne sont pas soumises au levage variable, ce qui signifie que les déclarations let ne se déplacent pas en haut du contexte d'exécution actuel." - Quoi qu'il en soit, j'ai apporté quelques améliorations à ma réponse qui devraient clarifier la différence de comportement de levage entre letet var!
John Slegers
1
Votre réponse s'est beaucoup améliorée (j'ai soigneusement vérifié). Notez que le même lien auquel vous avez fait référence dans votre commentaire indique également: "La variable (let) est dans une" zone morte temporelle "depuis le début du bloc jusqu'à ce que l'initialisation soit traitée." Cela signifie que «l'identifiant» (la chaîne de texte «réservé» pour pointer vers «quelque chose») est déjà réservé dans la portée pertinente, sinon il ferait partie de la portée racine / hôte / fenêtre. Pour moi personnellement, «hisser» ne signifie rien de plus que réserver / lier les «identifiants» déclarés à leur portée pertinente; à l'exclusion de leur initialisation / affectation / modifiable!
GitaarLAB
Et .. + 1. Cet article de Kyle Simpson que vous avez lié est une excellente lecture, merci pour cela! Il est également clair au sujet de la "zone morte temporelle" alias "TDZ". Une chose intéressante que j'aimerais ajouter: j'ai lu sur MDN letet j'ai constété recommandé de ne l'utiliser que lorsque vous avez réellement besoin de leurs fonctionnalités supplémentaires , car l'application / la vérification de ces fonctionnalités supplémentaires (comme la constante d'écriture seule) entraîne `` plus de travail '(et des noeuds de portée supplémentaires dans l'arborescence de portée) pour les moteurs (actuels) à appliquer / vérifier / vérifier / configurer.
GitaarLAB
1
Notez que MDN indique qu'IE interprète correctement let. Lequel est-ce? developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Katinka Hesselink
146

Voici une explication du letmot - clé avec quelques exemples.

letfonctionne très bien var. La principale différence est que la portée d'une varvariable est la fonction englobante entière

Ce tableau sur Wikipedia montre quels navigateurs prennent en charge Javascript 1.7.

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

Ben S
la source
5
Le bit clé du texte du document lié semble être «laisse fonctionner un peu comme var. La principale différence est que la portée d'une variable var est la fonction englobante entière».
Michael Burr
50
Bien qu'il soit techniquement correct de dire qu'IE ne le prend pas en charge, il est plus correct de dire qu'il s'agit d'une extension uniquement pour Mozilla.
olliej
55
@olliej, Mozilla est en fait juste en avance sur le jeu. Voir page 19 de ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf
Tyler Crompton
@TylerCrompton, ce n'est que l'ensemble des mots réservés depuis des années. Lorsque mozilla a été ajouté, il s'agissait purement d'une extension de mozilla, sans spécification connexe. ES6 devrait définir le comportement des instructions let, mais cela est venu après que mozilla a introduit la syntaxe. N'oubliez pas que moz a également E4X, qui est entièrement mort et moz uniquement.
olliej
9
IE11 a ajouté la prise en charge de let msdn.microsoft.com/en-us/library/ie/dn342892%28v=vs.85%29.aspx
eloyesp
112

Il manque un point à la réponse acceptée:

{
  let a = 123;
};

console.log(a); // ReferenceError: a is not defined
Lcf.vs
la source
19
La réponse acceptée n'explique PAS ce point dans son exemple. La réponse acceptée ne l'a démontré que dans un forinitialiseur de boucle, rétrécissant considérablement le champ d'application des limitations de let. A voté.
Jon Davis
37
@ stimpy77 Il indique explicitement "let est limité au bloc englobant le plus proche"; faut-il inclure tous les moyens qui se manifestent?
Dave Newton
6
il y avait beaucoup d'exemples et aucun d'eux n'a correctement démontré la question .. J'aurais peut-être voté à la fois la réponse acceptée et celle-ci?
Jon Davis
5
Cette contribution démontre qu'un "bloc" peut simplement être un ensemble de lignes entre crochets; c'est-à-dire qu'il n'a pas besoin d'être associé à une sorte de flux de contrôle, de boucle, etc.
webelo
81

let

Portée du bloc

Les variables déclarées à l'aide du letmot clé ont une portée de bloc, ce qui signifie qu'elles ne sont disponibles que dans le bloc 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 letne 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

A l'intérieur d'une fonction (mais à l'extérieur d'un bloc), leta 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 d' letun 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

À l'intérieur d'une boucle

Les variables déclarées avec des letboucles in 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 fermetures

Si vous utilisez letau lieu de vardans 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 temporelle

En raison de la zone morte temporelle , les variables déclarées à l'aide letne sont pas accessibles avant d'être déclarées. Tenter de le faire génère une erreur.

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

Pas de nouvelle 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 letdu même identifiant qu'une autre variable 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

constest 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 constne 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().

Un 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
Michał Perłakowski
la source
51

Voici un exemple de la différence entre les deux (le support vient de démarrer pour Chrome):
entrez la description de l'image ici

Comme vous pouvez le voir, la var jvariable a toujours une valeur en dehors de l'étendue de la boucle for (étendue de bloc), mais la let ivariable 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);

vlio20
la source
2
Quel outil est-ce que je regarde ici?
Barton
20
Chrome devtools
vlio20
En tant que développeur d'applets de bureau pour Cinnamon, je n'ai pas été exposé à des outils aussi brillants.
Barton
48

Il existe quelques différences subtiles - la letportée se comporte plus comme la portée variable dans plus ou moins toutes les autres langues.

Par exemple, il s'étend au bloc englobant, ils n'existent pas avant d'être déclarés, etc.

Cependant, il convient de noter que ce letn'est qu'une partie des implémentations Javascript plus récentes et prend en charge divers degrés de navigateur .

olliej
la source
11
Il convient également de noter que ECMAScript est la norme et letest inclus dans le projet de 6e édition et sera très probablement dans la spécification finale.
Richard Ayotte
23
C'est la différence que font 3 ans: D
olliej
4
Je viens de publier cette question et en 2012, il est toujours le cas que seuls les navigateurs Mozilla prennent en charge let. Safari, IE et Chome ne le font pas tous.
pseudosavant
2
L'idée de créer accidentellement une portée partielle de bloc en cas d'accident est un bon point, attention, letne pas hisser, pour utiliser une variable définie par une letdéfinie en haut de votre bloc. Si vous avez une ifinstruction qui est plus que quelques lignes de code, vous pouvez oublier que vous ne pouvez pas utiliser cette variable tant qu'elle n'est pas définie. GRAND POINT !!!
Eric Bishard
2
@EricB: oui et non: "Dans ECMAScript 2015, let va hisser la variable en haut du bloc. Cependant, référencer la variable dans le bloc avant la déclaration de variable entraîne une ReferenceError (ma note: au lieu de bonne vieille undefined). La La variable se trouve dans une "zone morte temporelle" depuis le début du bloc jusqu'à ce que la déclaration soit traitée. " Il en va de même pour les "instructions switch car il n'y a qu'un seul bloc sous-jacent". Source: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
GitaarLAB
29

La principale différence est la différence de portée , alors que let ne peut être disponible qu'à l'intérieur de la portée déclarée, 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 laquelle il est utilisé. Ceci est différent du mot-clé var , qui définit une variable globalement ou localement pour 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 tout sous-bloc contenu. De cette façon, 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:

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, laissez , 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é à l'intérieur d'un bloc, let 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

N'oubliez pas non plus qu'il s'agit de la fonctionnalité ECMA6, il n'est donc pas encore entièrement pris en charge, il est donc préférable de toujours le transpiler vers ECMA5 en utilisant Babel, etc. ... pour plus d'informations sur le site Web de Babel

Alireza
la source
24
  • Variable sans levage

    letne sera pas hissé sur toute l'étendue du bloc dans lequel ils apparaissent. En revanche, varpourrait être hissé 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, les deux varet letsont hissés .

  • Collecte des ordures

    L'étendue des blocs de letest utile concerne les fermetures et la récupération de place 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 clickrappel du gestionnaire n'a pas du tout besoin de la hugeDatavariable. Théoriquement, après les process(..)exécutions, l'énorme structure de données hugeDatapourrait être récupérée. Cependant, il est possible que certains moteurs JS devront toujours conserver cette structure énorme, car la clickfonction a une fermeture sur toute l'étendue.

    Cependant, la portée du bloc peut rendre cette énorme structure de données à la 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

    letdans la boucle peut le lier à nouveau à chaque itération de la boucle, en veillant à lui réaffecter la valeur de la fin de l'itération de 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 varparlet

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

    Parce que letcréer un nouvel environnement lexical avec ces noms pour a) l'expression d'initialisation b) chaque itération (surtout pour évaluer l'expression d'incrémentation), plus de détails sont ici .

zangw
la source
4
Oui, ils sont hissés, mais se comportent comme s'ils n'étaient pas hissés à cause de la zone morte temporelle (roulement de tambour) - un nom très dramatique pour un identifiant qui n'est accessible que lorsqu'il est déclaré :-)
Drenai
Alors laissez est hissé, mais indisponible? En quoi est-ce différent de «non hissé»?
N-ate
J'espère que Brian ou Bergi reviendront pour répondre à cette question. La déclaration de location est-elle hissée, mais pas la cession? Merci!
N-ate
1
@ N-ate, Voici un article de Bergi, vous y trouverez peut-être une réponse.
zangw
Il est intéressant de noter qu'il est même appelé levage lorsqu'il s'agit de louer. J'obtiens que techniquement le moteur d'analyse le pré-capture, mais à toutes fins utiles, un programmeur devrait le traiter comme s'il n'existait pas. En revanche, le hissage de var a des implications pour un programmeur.
N-ate
19

Voici un exemple à ajouter à ce que d'autres ont déjà écrit. Supposons que vous vouliez créer un tableau de fonctions,, adderFunctionsoù chaque fonction prend un seul argument Number et renvoie la somme de l'argument et de l'index de la fonction dans le tableau. Essayer de générer adderFunctionsavec une boucle en utilisant le varmot - clé ne fonctionnera pas comme quelqu'un pourrait l'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 ila portée de s'étend au-delà de l'itération du forbloc dans lequel chaque fonction a été créée. Au lieu de cela, à la fin de la boucle, la ifermeture de chaque fonction fait référence à ila valeur de 'à la fin de la boucle (1000) pour chaque fonction anonyme dans adderFunctions. Ce n'est pas du tout ce que nous voulions: nous avons maintenant un tableau de 1000 fonctions différentes en mémoire avec exactement le même comportement. Et si nous mettons à jour la valeur de i, la mutation affectera tous les adderFunctions.

Cependant, nous pouvons réessayer en utilisant le letmot - clé:

// 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, ion rebondit à chaque itération de la forboucle. Chaque fonction conserve désormais la valeur de iau moment de sa création et adderFunctionsse comporte comme prévu.

Maintenant, mélangez l'image des deux comportements et vous verrez probablement pourquoi il n'est pas recommandé de mélanger le plus récent letet constle plus ancien vardans le même script. Cela peut entraîner un code déroutant spectaculaire.

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.

REMARQUE: il s'agit d'un exemple pédagogique destiné à démontrer le comportement var/ letdans les boucles et avec les fermetures de fonctions qui seraient également faciles à comprendre. Ce serait une façon 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.

abroz
la source
2
@aborz: également une syntaxe de fonction anonyme très cool dans le deuxième exemple. C'est juste ce à quoi je suis habitué en C #. J'ai appris quelque chose aujourd'hui.
Barton
Correction: Techniquement, la syntaxe de la fonction Flèche décrite ici => developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Barton
3
En fait, vous n'en avez pas besoin let value = i;. L' forinstruction crée un bloc lexical.
Brosse à dents du
17

La différence réside dans la portée des variables déclarées avec chacune.

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

  1. letles variables ne sont visibles que dans leur bloc englobant le plus proche ( { ... }).
  2. letles variables ne sont utilisables que dans les lignes de code qui se produisent après la déclaration de la variable (même si elles sont hissées !).
  3. letles variables ne peuvent pas être redéclarées par un varou let.
  4. Les letvariables globales ne sont pas ajoutées à l' windowobjet global .
  5. letles variables sont faciles à utiliser avec les fermetures (elles ne provoquent pas de conditions de concurrence ).

Les restrictions imposées par letréduisent la visibilité des variables et augmentent la probabilité que des collisions de noms inattendues soient détectées 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 letvariables sont moins susceptibles de causer des problèmes lorsqu'elles sont utilisées dans de grands programmes ou lorsque des cadres développés indépendamment sont combinés de manière nouvelle et inattendue.

varpeut toujours être utile si vous êtes sûr 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 varfor exports peut être supplantée si la exportmigration hors de l'espace du transpilateur et vers le langage principal.

Exemples

1. Aucune utilisation en dehors du bloc englobant le plus proche: ce bloc de code générera une erreur de référence car la deuxième utilisation de xse 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 des varœuvres.

2. Pas d'utilisation avant la déclaration:
ce bloc de code lancera un ReferenceErroravant que le code puisse être exécuté car il xest 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 varanalyse et s'exécute sans lever d'exceptions.

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

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

4. Mondiaux 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 les fermetures: les variables déclarées avec varne fonctionnent pas bien avec les fermetures à l'intérieur des boucles. Voici une boucle simple qui produit la séquence de valeurs que la variable ia à différents moments:

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 respectons let. En revanche, si nous avions utilisé à la var iplace:

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

... la boucle produit cinq fois "i is 5" de façon inattendue:

i is 5
i is 5
i is 5
i is 5
i is 5
mormegil
la source
5
Le n ° 5 n'est pas causé par une condition de concurrence. En utilisant varau lieu de let, le code est équivalent à: var i = 0; while (i < 5) { doSomethingLater(); i++; } iest en dehors de la fermeture, et au moment où il doSomethingLater()est exécuté, ia déjà été incrémenté 5 fois, donc la sortie est i is 5cinq fois. En utilisant let, la variable se itrouve dans la fermeture, donc chaque appel asynchrone obtient sa propre copie de iau lieu d'utiliser celle «globale» qui a été créée avec var.
Daniel T.
@DanielT .: Je ne pense pas que la transformation de la levée de la définition de variable hors de l'initialiseur de boucle n'explique rien. C'est simplement la définition normale de la sémantique de for. Une transformation plus précise, bien que plus compliquée, est la classique for (var i = 0; i < 5; i++) { (function(j) { setTimeout(_ => console.log(i est $ {j} ), 125/*ms*/); })(i); }qui introduit un "enregistrement d'activation de fonction" pour enregistrer chaque valeur de iavec le nom de l' jintérieur de la fonction.
mormegil
14

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
}
Abdennour TOUMI
la source
13

let est intéressant, car il nous permet de faire quelque chose comme ça:

(() => {
    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 un 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].

Dmitry
la source
2
c'est la première fois que je vois quelqu'un agir comme un ombrage variable était souhaitable. non, le but de let n'est pas de permettre l'observation
John Haugeland
1
objectif? c'est une construction, vous pouvez l'utiliser comme bon vous semble, une des façons intéressantes est comme ça.
Dmitry
13

Portée du bloc VS:

La principale différence entre varet letest que les variables déclarées avec varont une portée de fonction . Alors que les fonctions déclarées avec letsont de portée bloc . 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 testVarest appelée, la variable foo, déclarée avec var, est toujours accessible en dehors de l' ifinstruction. Cette variable fooserait disponible partout dans le cadre de la testVar fonction .

variables avec let:

Lorsque la deuxième fonction testLetest appelée, la barre de variables, déclarée avec let, n'est accessible qu'à l'intérieur de l' ifinstruction. Étant donné que les variables déclarées avec letsont bloc scope (où un bloc est le code entre accolades , par exemple if{}, for{}, function{}).

let les variables ne sont pas hissées:

Une autre différence entre varet letest que les variables avec déclaré avec let ne sont pas hissées . Un exemple est la meilleure façon d'illustrer ce comportement:

les variables avec let ne sont pas hissées:

console.log(letVar);

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

les variables avec var ne sont hissées:

console.log(varVar);

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

Global letne s'attache pas à window:

Une variable déclarée avec letdans la portée globale (qui est du code qui n'est pas dans une fonction) n'est pas ajoutée en tant que propriété sur l' windowobjet global . Par exemple (ce code a une 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


Quand faut- letil l'utiliser var?

Utilisez- letle varchaque fois que vous le pouvez, car il est simplement plus précis. Cela réduit les conflits de nommage potentiels qui peuvent survenir lors du traitement d'un grand nombre de variables. varpeut être utilisé lorsque vous voulez qu'une variable globale soit explicitement sur l' windowobjet (pensez toujours soigneusement si c'est vraiment nécessaire).

Willem van der Veen
la source
9

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 permet 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;
RDoc
la source
9

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

letet constest la portée du 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

Shahsavan musulman
la source
8

Lors de l'utilisation let

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

letles variables ne sont pas accessibles dans l' windowobjet car elles ne sont pas 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 var

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

varles variables sont accessibles dans l' windowobjet car elles ne sont pas 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'entrevue les plus célèbres sur la portée peut également suffire à l'utilisation exacte de letet varcomme ci-dessous;

Lors de l'utilisation 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, la variable est délimitée et possède sa propre copie.

Lors de l'utilisation 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 délimitée et a une copie partagée.

Ankur Soni
la source
8

En termes les plus élémentaires,

for (let i = 0; i < 5; i++) {
  // i accessible ✔️
}
// i not accessible ❌

for (var i = 0; i < 5; i++) {
  // i accessible ✔️
}
// i accessible ✔️

⚡️ Bac à sable pour jouer ↓

Modifier let vs var

Hasan Sefa Ozalp
la source
7

Si je lis bien les spécifications, alors let heureusement, on peut également tirer parti pour éviter les fonctions auto-appelantes utilisées pour simuler des membres privés uniquement - un modèle de conception populaire qui diminue la lisibilité du code, complique le débogage, qui n'ajoute aucune protection de code réelle ou autre avantage - sauf peut-être pour satisfaire quelqu'un désir de sémantique, alors arrêtez 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 « Émulation d'interfaces privées »

Daniel Sokolowski
la source
Pouvez-vous expliquer comment les expressions de fonction immédiatement appelées ne fournissent pas de «protection de code» et le letfont? (Je suppose que vous voulez dire IIFE avec «fonction auto-invoquante».)
Robert Siemer
Et pourquoi vous installez-vous hiddenPropertydans le constructeur? Il n'y en a qu'une hiddenPropertypour toutes les instances de votre «classe».
Robert Siemer
4

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)
zloctb
la source
s'il vous plaît qu'est-ce que cela signifie let { type, name, value } = node;? vous créez un nouvel objet avec 3 propriétés type / nom / valeur et les initialisez avec les valeurs de propriétés du nœud?
AlainIb
Dans l'exemple 3, vous redéclarez le nœud qui provoque une exception. Tous ces exemples fonctionnent également parfaitement avec var.
Rehan Haider
4

let vs var. C'est une question de portée .

Les variables var sont globales et sont accessibles pratiquement partout, tandis que les variables let 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 console.logs; il devient hors de portée dans le 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.
daCoda
la source
4

ES6 a introduit deux nouveaux mots clés ( let et const ) alternatifs à var .

Lorsque vous avez besoin d'une décélération de niveau bloc, vous pouvez utiliser let et const au lieu de var.

Le tableau ci-dessous résume la différence entre var, let et const

entrez la description de l'image ici

Srikrushna
la source
3

let fait partie d'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
}
vipul jain
la source
3

Ce qui suit montre comment «let» et «var» sont différents dans la portée:

let gfoo = 123;
if (true) {
    let gfoo = 456;
}
console.log(gfoo); // 123

var hfoo = 123;
if (true) {
    var hfoo = 456;
}
console.log(hfoo); // 456

Le gfoo, défini par letinitialement est dans la portée globale , et lorsque nous déclarons à gfoonouveau à l'intérieur de if clausesa portée modifiée et lorsqu'une nouvelle valeur est affectée à la variable à l'intérieur de cette portée, cela n'affecte pas la portée globale.

Alors que hfoo, défini par varest initialement dans la portée globale , mais encore une fois lorsque nous le déclarons à l'intérieur de if clause, il considère la portée globale hfoo, bien que var ait été utilisé à nouveau pour le déclarer. Et lorsque nous réaffectons sa valeur, nous constatons que la portée globale hfoo est également affectée. C'est la principale différence.

Piklu Dey
la source
2

Comme mentionné ci-dessus:

La différence est la portée. varest limité au bloc fonctionnel le plus proche et letlimité au bloc englobant le plus proche , qui peut être plus petit qu'un bloc fonctionnel. Les deux sont globales si en dehors de tout bloc. Voyons un exemple:

Exemple 1:

Dans mes deux exemples, j'ai une fonction myfunc. myfunccontient une variable myvarégale à 10. Dans mon premier exemple, je vérifie si elle myvarest égale à 10 ( myvar==10). Si oui, je déclare une variable myvar(maintenant j'ai deux variables myvar) en utilisant un varmot-clé 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 de myvarsur ma console. Si vous regardez la sortie de myfunc, la myvarvaleur est égale à 20.

laisser le mot-clé

Exemple2: Dans mon deuxième exemple, au lieu d'utiliser un varmot clé dans mon bloc conditionnel, je déclare myvarutiliser un letmot clé. Maintenant, quand j'appelle, myfunc j'obtiens deux sorties différentes: myvar=20et myvar=10.

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

N Randhawa
la source
3
Veuillez ne pas publier d'images de code, cela est considéré comme une mauvaise pratique sur SO car il ne sera pas consultable pour les futurs utilisateurs (ainsi que les problèmes d'accessibilité). De plus, cette réponse n'ajoute rien que les autres réponses n'ont pas déjà abordées.
inostia
2

Je veux 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 a un environnement variable et un environnement extérieur (son environnement lexical).

Pendant la phase de création d'un contexte d'exécution, var, let et const conserveront toujours sa variable en mémoire avec une valeur non définie dans l'environnement variable du contexte d'exécution donné. La différence réside dans la phase d'exécution. Si vous utilisez référence une variable définie avec var avant de lui attribuer une valeur, elle ne sera simplement pas dé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'est pas déclarée. Si vous essayez de l'utiliser avant qu'il ne soit déclaré, une exception sera déclenchée pendant la phase d'exécution du contexte d'exécution. Maintenant, la variable sera toujours en mémoire, gracieuseté de 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 trouver la variable dans l'environnement variable du contexte d'exécution actuel, il remontera la chaîne de portée (l'environnement externe) et vérifiera l'environnement variable de l'environnement externe pour la variable. S'il ne le trouve pas, il continuera de rechercher la chaîne de portée. Ce n'est pas le cas avec let et const.

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

ES6 introduit également le mot clé const pour déclarer des variables. const a également une portée de bloc. La différence entre let et const est que les variables const doivent être déclarées à l'aide d'un initialiseur, sinon elles généreront une erreur.

Et, 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, ce sera l'objet fenêtre dans les navigateurs. Ce n'est pas le cas pour let ou const.

Donato
la source
2

Je pense que les termes et la plupart des exemples sont un peu écrasants. Le principal problème que j'ai eu personnellement avec la différence est de comprendre ce qu'est un "bloc". À un moment donné, je me suis rendu compte qu'un bloc serait constitué de crochets, sauf pour l' IFinstruction. une parenthèse ouvrante {d'une fonction ou d'une boucle définira un nouveau bloc, tout ce qui y est défini let, ne sera pas disponible après la parenthèse fermante }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);

Démence
la source
1

Maintenant, je pense qu'il y a une meilleure 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 commenceront à utiliser let ici après afin d'avoir une portée similaire en JavaScript comme d'autres langages, Java, C #, etc.

Les personnes n'ayant pas une compréhension claire de la portée de JavaScript avaient l'habitude de commettre l'erreur plus tôt.

Le levage n'est pas pris en charge à l'aide 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.

swaraj patil
la source
Pour une compréhension approfondie à ce sujet, consultez le lien - davidwalsh.name/for-and-against-let
swaraj patil
1

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

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

let, est un signal indiquant que la variable peut être réaffectée, comme un compteur dans une boucle ou un échange de valeur dans un algorithme. Il signale également que la variable sera utilisée uniquement dans le bloc dans lequel elle est définie, qui n'est pas toujours la fonction conteneur entière.

varest désormais le signal le plus faible disponible lorsque vous définissez une variable en JavaScript. La variable peut ou non être réaffectée, et la variable peut ou non être utilisée pour une fonction entière, ou simplement à des fins de bloc ou de boucle.

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

anandharshan
la source