Quelle est la différence entre l'utilisation de « laisser » et « var »?
-
11-09-2019 - |
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
?
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:
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 commevar
. La principale différence est que la portée d'une variable devar
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):
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 Levagelet
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
etlet
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 variablehugeData
du tout. En théorie, après l'exécution deprocess(..)
, l'énorme structure de donnéeshugeData
pourrait être garbage collection. Cependant, il est possible que certains moteurs JS aura toujours garder cette énorme structure, la fonction declick
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
aveclet
// 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:
- variables
let
ne sont visibles que dans leur englobante le plus proche bloc ({ ... }
). - 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 !). - variables
let
ne peuvent pas être redéclarées par unevar
ultérieure oulet
. - Les variables globales de
let
ne sont pas ajoutés à l'objet globalwindow
. - 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é survar
?
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.
Comme mentionné ci-dessus:
La différence est la portée.
var
est scope au plus proche fonction bloc etlet
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.