ECMAScript 6 a introduit la déclaration let
. J'ai entendu dire que c'était une variable "locale", mais je ne sais toujours pas comment elle se comporte différemment du mot clé var
.
Quelles sont les différences? Quand let
devrait-il être utilisé par rapport à var
?
La différence est la portée. var
est limité au bloc de fonction le plus proche et let
est limité au bloc englobant le plus proche, qui peut être plus petit qu'un bloc de fonction Les deux sont globaux s'ils sont en dehors d'un bloc.
De plus, les variables déclarées avec let
ne sont pas accessibles avant d'être déclarées dans leur bloc englobant. Comme on le voit dans la démo, une exception ReferenceError sera renvoyée.
Démo :
var html = '';
write('#### global ####\n');
write('globalVar: ' + globalVar); //undefined, but visible
try {
write('globalLet: ' + globalLet); //undefined, *not* visible
} catch (exception) {
write('globalLet: exception');
}
write('\nset variables');
var globalVar = 'globalVar';
let globalLet = 'globalLet';
write('\nglobalVar: ' + globalVar);
write('globalLet: ' + globalLet);
function functionScoped() {
write('\n#### function ####');
write('\nfunctionVar: ' + functionVar); //undefined, but visible
try {
write('functionLet: ' + functionLet); //undefined, *not* visible
} catch (exception) {
write('functionLet: exception');
}
write('\nset variables');
var functionVar = 'functionVar';
let functionLet = 'functionLet';
write('\nfunctionVar: ' + functionVar);
write('functionLet: ' + functionLet);
}
function blockScoped() {
write('\n#### block ####');
write('\nblockVar: ' + blockVar); //undefined, but visible
try {
write('blockLet: ' + blockLet); //undefined, *not* visible
} catch (exception) {
write('blockLet: exception');
}
for (var blockVar = 'blockVar', blockIndex = 0; blockIndex < 1; blockIndex++) {
write('\nblockVar: ' + blockVar); // visible here and whole function
};
for (let blockLet = 'blockLet', letIndex = 0; letIndex < 1; letIndex++) {
write('blockLet: ' + blockLet); // visible only here
};
write('\nblockVar: ' + blockVar);
try {
write('blockLet: ' + blockLet); //undefined, *not* visible
} catch (exception) {
write('blockLet: exception');
}
}
function write(line) {
html += (line ? line : '') + '<br />';
}
functionScoped();
blockScoped();
document.getElementById('results').innerHTML = html;
<pre id="results"></pre>
Ils sont très similaires lorsqu'ils sont utilisés comme ceci en dehors d'un bloc de fonction.
let me = 'go'; // globally scoped
var i = 'able'; // globally scoped
Cependant, les variables globales définies avec let
ne seront pas ajoutées en tant que propriétés sur l'objet global window
comme celles définies avec var
.
console.log(window.me); // undefined
console.log(window.i); // 'able'
Ils sont identiques lorsqu'ils sont utilisés comme ceci dans un bloc de fonction.
function ingWithinEstablishedParameters() {
let terOfRecommendation = 'awesome worker!'; //function block scoped
var sityCheerleading = 'go!'; //function block scoped
}
Voici la différence. let
n'est visible que dans la boucle for()
et var
est visible pour l'ensemble de la fonction.
function allyIlliterate() {
//tuce is *not* visible out here
for( let tuce = 0; tuce < 5; tuce++ ) {
//tuce is only visible in here (and in the for() parentheses)
//and there is a separate tuce variable for each iteration of the loop
}
//tuce is *not* visible out here
}
function byE40() {
//nish *is* visible out here
for( var nish = 0; nish < 5; nish++ ) {
//nish is visible to the whole function
}
//nish *is* visible out here
}
En supposant le mode strict, var
vous permettra de déclarer de nouveau la même variable dans la même portée. Par contre, let
ne sera pas:
'use strict';
let me = 'foo';
let me = 'bar'; // SyntaxError: Identifier 'me' has already been declared
'use strict';
var me = 'foo';
var me = 'bar'; // No problem, `me` is replaced.
let
peut également être utilisé pour éviter les problèmes de fermeture. Il lie une nouvelle valeur plutôt que de conserver une ancienne référence, comme indiqué dans les exemples ci-dessous.
for(var i = 1; i < 6; i++) {
document.getElementById('my-element' + i)
.addEventListener('click', function() { alert(i) })
}
Le code ci-dessus illustre un problème classique de fermeture de JavaScript. La référence à la variable i
est stockée dans la fermeture du gestionnaire de clics, plutôt que la valeur réelle de i
.
Chaque gestionnaire de clic se réfère au même objet car il n’ya qu’un seul objet compteur qui en contient 6, de sorte que vous en obtenez six à chaque clic.
La solution de contournement générale consiste à envelopper cela dans une fonction anonyme et à passer i
en argument. De tels problèmes peuvent également être évités maintenant en utilisant let
à la place de var
, comme indiqué dans le code ci-dessous.
DEMO (testé sous Chrome et Firefox 50)
'use strict';
for(let i = 1; i < 6; i++) {
document.getElementById('my-element' + i)
.addEventListener('click', function() { alert(i) })
}
Voici une explication du mot clé let
avec quelques exemples.
laissez fonctionne très bien comme var. La principale différence est que la portée d'une variable var est la fonction englobante entière
Ce tableau sur Wikipedia indique les navigateurs prenant en charge Javascript 1.7.
Notez que seuls les navigateurs Mozilla et Chrome le prennent en charge. IE, Safari et potentiellement d'autres ne le font pas.
let
et var
?var
est connue dans tout le répertoire de la fonction dans laquelle elle est définie depuis le début de la fonction. (*)let
n'est connue que dans le bloc il est défini dans, à partir du moment où elle est définie. _ {(**)} _Pour comprendre la différence, considérons le code suivant:
// i IS NOT known here
// j IS NOT known here
// k IS known here, but undefined
// l IS NOT known here
function loop(arr) {
// i IS known here, but undefined
// j IS NOT known here
// k IS known here, but has a value only the second time loop is called
// l IS NOT known here
for( var i = 0; i < arr.length; i++ ) {
// i IS known here, and has a value
// j IS NOT known here
// k IS known here, but has a value only the second time loop is called
// l IS NOT known here
};
// i IS known here, and has a value
// j IS NOT known here
// k IS known here, but has a value only the second time loop is called
// l IS NOT known here
for( let j = 0; j < arr.length; j++ ) {
// i IS known here, and has a value
// j IS known here, and has a value
// k IS known here, but has a value only the second time loop is called
// l IS NOT known here
};
// i IS known here, and has a value
// j IS NOT known here
// k IS known here, but has a value only the second time loop is called
// l IS NOT known here
}
loop([1,2,3,4]);
for( var k = 0; k < arr.length; k++ ) {
// i IS NOT known here
// j IS NOT known here
// k IS known here, and has a value
// l IS NOT known here
};
for( let l = 0; l < arr.length; l++ ) {
// i IS NOT known here
// j IS NOT known here
// k IS known here, and has a value
// l IS known here, and has a value
};
loop([1,2,3,4]);
// i IS NOT known here
// j IS NOT known here
// k IS known here, and has a value
// l IS NOT known here
Ici, nous pouvons voir que notre variable j
n'est connue que dans la première boucle for, mais pas avant et après. Cependant, notre variable i
est connue dans toute la fonction.
En outre, considérez que les variables de portée de bloc ne sont pas connues avant leur déclaration car elles ne sont pas levées. Vous n'êtes également pas autorisé à redéclarer la même variable de périmètre de bloc dans le même bloc. Cela rend les variables à portée de bloc moins sujettes aux erreurs que les variables à portée globale ou fonctionnelle, qui sont levées et qui ne produisent aucune erreur en cas de déclarations multiples.
let
aujourd'hui?Certains diront qu'à l'avenir, nous utiliserons UNIQUEMENT les instructions let et que les instructions var deviendront obsolètes. Gourou JavaScript Kyle Simpson a écrit un article très élaboré expliquant pourquoi ce n'est pas le cas .
Aujourd'hui, cependant, ce n'est définitivement pas le cas. En fait, nous devons nous demander s'il est prudent d'utiliser l'instruction let
. La réponse à cette question dépend de votre environnement:
Si vous écrivez du code JavaScript côté serveur ( Node.js ), vous pouvez utiliser en toute sécurité l'instruction let
.
Si vous écrivez du code JavaScript côté client et utilisez un transpiler (comme Traceur ), vous pouvez utiliser l'instruction let
en toute sécurité, mais votre code sera probablement tout sauf optimal en termes de performances.
Si vous écrivez du code JavaScript côté client et n'utilisez pas de transpiler, vous devez envisager la prise en charge du navigateur.
Aujourd'hui, 8 juin 2018, il reste encore des navigateurs qui ne supportent pas let
!
Pour un aperçu à jour des navigateurs qui prennent en charge l'instruction let
au moment de lire cette réponse, voir this Can I Use
page .
(*)) Les variables à portée globale et fonctionnelle peuvent être initialisées et utilisées avant d'être déclarées, car les variables JavaScript sont hoisted . Cela signifie que les déclarations sont toujours beaucoup plus en haut .
(**) Les variables de périmètre de bloc ne sont pas levées}
La réponse acceptée manque un point:
{
let a = 123;
};
console.log(a); // ReferenceError: a is not defined
let
Les variables déclarées à l'aide du mot clé let
ont une portée de bloc, ce qui signifie qu'elles ne sont disponibles que dans le bloc block dans lequel elles ont été déclarées.
Au niveau supérieur, les variables déclarées à l'aide de let
ne créent pas de propriétés sur l'objet global.
var globalVariable = 42;
let blockScopedVariable = 43;
console.log(globalVariable); // 42
console.log(blockScopedVariable); // 43
console.log(this.globalVariable); // 42
console.log(this.blockScopedVariable); // undefined
Dans une fonction (mais en dehors d'un bloc), let
a la même portée que var
.
(() => {
var functionScopedVariable = 42;
let blockScopedVariable = 43;
console.log(functionScopedVariable); // 42
console.log(blockScopedVariable); // 43
})();
console.log(functionScopedVariable); // ReferenceError: functionScopedVariable is not defined
console.log(blockScopedVariable); // ReferenceError: blockScopedVariable is not defined
Les variables déclarées à l'aide de let
à l'intérieur d'un bloc sont inaccessibles en dehors de ce bloc.
{
var globalVariable = 42;
let blockScopedVariable = 43;
console.log(globalVariable); // 42
console.log(blockScopedVariable); // 43
}
console.log(globalVariable); // 42
console.log(blockScopedVariable); // ReferenceError: blockScopedVariable is not defined
Les variables déclarées avec let
dans les boucles ne peuvent être référencées qu'à l'intérieur de cette boucle.
for (var i = 0; i < 3; i++) {
var j = i * 2;
}
console.log(i); // 3
console.log(j); // 4
for (let k = 0; k < 3; k++) {
let l = k * 2;
}
console.log(typeof k); // undefined
console.log(typeof l); // undefined
// Trying to do console.log(k) or console.log(l) here would throw a ReferenceError.
Si vous utilisez let
au lieu de var
dans une boucle, vous obtenez une nouvelle variable à chaque itération. Cela signifie que vous pouvez utiliser en toute sécurité une fermeture dans une boucle.
// Logs 3 thrice, not what we meant.
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 0);
}
// Logs 0, 1 and 2, as expected.
for (let j = 0; j < 3; j++) {
setTimeout(() => console.log(j), 0);
}
En raison de la zone morte temporelle , les variables déclarées à l'aide de let
ne sont pas accessibles avant d'être déclarées. Tenter de le faire renvoie une erreur.
console.log(noTDZ); // undefined
var noTDZ = 43;
console.log(hasTDZ); // ReferenceError: hasTDZ is not defined
let hasTDZ = 42;
Vous ne pouvez pas déclarer la même variable plusieurs fois à l'aide de let
. Vous ne pouvez pas non plus déclarer une variable à l'aide de let
avec le même identifiant qu'une autre variable déclarée à l'aide de var
.
var a;
var a; // Works fine.
let b;
let b; // SyntaxError: Identifier 'b' has already been declared
var c;
let c; // SyntaxError: Identifier 'c' has already been declared
const
const
est assez similaire à let
— il a une portée de bloc et a TDZ. Il y a cependant deux choses différentes.
La variable déclarée à l'aide de const
ne peut pas être réaffectée.
const a = 42;
a = 43; // TypeError: Assignment to constant variable.
Notez que cela ne signifie pas que la valeur est immuable. Ses propriétés peuvent encore être modifiées.
const obj = {};
obj.a = 42;
console.log(obj.a); // 42
Si vous voulez avoir un objet immuable, vous devez utiliser Object.freeze()
.
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
Voici un exemple de la différence entre les deux (support qui vient de commencer pour chrome):
Comme vous pouvez le constater, la variable var j
a toujours une valeur en dehors de l'étendue de la boucle for, mais la variable let i
n'est pas définie en dehors de l'étendue de la boucle for.
"use strict";
console.log("var:");
for (var j = 0; j < 2; j++) {
console.log(j);
}
console.log(j);
console.log("let:");
for (let i = 0; i < 2; i++) {
console.log(i);
}
console.log(i);
Il existe quelques différences subtiles - la portée de let
se comporte davantage comme le fait la portée de variable dans plus ou moins d’autres langues.
par exemple. Cela concerne le bloc englobant, ils n'existent pas avant leur déclaration, etc.
Toutefois, il est à noter que let
n'est qu'une partie des implémentations Javascript plus récentes et prend en charge divers degrés de support pour browser .
Variable non levante
let
ne relancera pas à toute l'étendue du bloc dans lequel ils apparaissent. En revanche, var
pourrait remonter comme ci-dessous.
{
console.log(cc); // undefined. Caused by hoisting
var cc = 23;
}
{
console.log(bb); // ReferenceError: bb is not defined
let bb = 23;
}
En fait, Per @Bergi, var
et let
sont tous deux hissés .
Collecte des ordures
La portée du bloc de let
est utile pour les fermetures et le garbage collection afin de récupérer la mémoire. Considérer,
function process(data) {
//...
}
var hugeData = { .. };
process(hugeData);
var btn = document.getElementById("mybutton");
btn.addEventListener( "click", function click(evt){
//....
});
Le rappel du gestionnaire click
n'a pas du tout besoin de la variable hugeData
. Théoriquement, après l'exécution de process(..)
, l'énorme structure de données hugeData
pourrait être récupérée. Cependant, il est possible que certains moteurs JS doivent encore conserver cette structure énorme, car la fonction click
a une fermeture sur toute la portée.
Cependant, la portée du bloc peut transformer cette énorme structure de données en déchets.
function process(data) {
//...
}
{ // anything declared inside this block can be garbage collected
let hugeData = { .. };
process(hugeData);
}
var btn = document.getElementById("mybutton");
btn.addEventListener( "click", function click(evt){
//....
});
let
boucles
let
dans la boucle peut le relier à chaque itération de la boucle, en s'assurant de la réaffecter à la valeur à partir de la fin de l'itération de la boucle précédente. Considérer,
// print '5' 5 times
for (var i = 0; i < 5; ++i) {
setTimeout(function () {
console.log(i);
}, 1000);
}
Cependant, remplacez var
par let
// print 1, 2, 3, 4, 5. now
for (let i = 0; i < 5; ++i) {
setTimeout(function () {
console.log(i);
}, 1000);
}
Parce que let
crée un nouvel environnement lexical avec ces noms pour a) l'expression d'initialiseur b) chaque itération (avant d'évaluer l'évaluation d'incrémentation), plus de détails sont ici .
La différence principale est la différence scope, alors que let ne peut être disponible qu'à l'intérieur du scope déclaré, comme dans la boucle for, var est accessible en dehors de la boucle par exemple. . De la documentation dans MDN (exemples également de MDN):
let vous permet de déclarer des variables dont la portée est limitée au bloc, à l'instruction ou à l'expression sur lequel elles sont utilisées. Cela diffère du mot-clé var, qui définit une variable globalement ou localement sur une fonction entière, quelle que soit la portée du bloc.
Les variables déclarées par let ont pour portée le bloc dans lequel elles sont définies, ainsi que dans tous les sous-blocs contenus. De cette façon, let fonctionne très bien comme var. La principale différence est que la portée d'une variable var correspond à l'ensemble de la fonction englobante:
function varTest() {
var x = 1;
if (true) {
var x = 2; // same variable!
console.log(x); // 2
}
console.log(x); // 2
}
function letTest() {
let x = 1;
if (true) {
let x = 2; // different variable
console.log(x); // 2
}
console.log(x); // 1
}`
Au niveau supérieur des programmes et des fonctions, let, contrairement à var, ne crée pas de propriété sur l'objet global. Par exemple:
var x = 'global';
let y = 'global';
console.log(this.x); // "global"
console.log(this.y); // undefined
Lorsqu'il est utilisé à l'intérieur d'un bloc, laisse limiter la portée de la variable à ce bloc. Notez la différence entre var dont la portée est à l'intérieur de la fonction où elle est déclarée.
var a = 1;
var b = 2;
if (a === 1) {
var a = 11; // the scope is global
let b = 22; // the scope is inside the if-block
console.log(a); // 11
console.log(b); // 22
}
console.log(a); // 11
console.log(b); // 2
N'oubliez pas non plus que c'est la fonctionnalité ECMA6, donc elle n'est pas encore totalement prise en charge. Il est donc préférable de toujours l'envoyer à ECMA5 avec Babel, etc. Pour plus d'informations sur visit babel website
Voici un exemple à ajouter à ce que d’autres ont déjà écrit. Supposons que vous souhaitiez créer un tableau de fonctions, adderFunctions
, où chaque fonction prend un seul argument Number et renvoie la somme de l'argument et l'index de la fonction dans le tableau. Essayer de générer adderFunctions
avec une boucle en utilisant le mot clé var
ne fonctionnera pas comme quelqu'un pourrait s'y attendre naïvement:
// An array of adder functions.
var adderFunctions = [];
for (var i = 0; i < 1000; i++) {
// We want the function at index i to add the index to its argument.
adderFunctions[i] = function(x) {
// What is i bound to here?
return x + i;
};
}
var add12 = adderFunctions[12];
// Uh oh. The function is bound to i in the outer scope, which is currently 1000.
console.log(add12(8) === 20); // => false
console.log(add12(8) === 1008); // => true
console.log(i); // => 1000
// It gets worse.
i = -8;
console.log(add12(8) === 0); // => true
Le processus ci-dessus ne génère pas le tableau de fonctions souhaité, car la portée de i
s'étend au-delà de l'itération du bloc for
dans lequel chaque fonction a été créée. Au lieu de cela, à la fin de la boucle, la i
dans la fermeture de chaque fonction fait référence à la valeur de i
à la fin de la boucle (1000) pour chaque fonction anonyme dans adderFunctions
. Ce n’était pas ce que nous voulions du tout: nous avons maintenant en mémoire un tableau de 1000 fonctions différentes avec exactement le même comportement. Et si nous mettons ensuite à jour la valeur de i
, la mutation affectera tous les adderFunctions
.
Cependant, nous pouvons essayer à nouveau en utilisant le mot clé let
:
// Let's try this again.
// NOTE: We're using another ES6 keyword, const, for values that won't
// be reassigned. const and let have similar scoping behavior.
const adderFunctions = [];
for (let i = 0; i < 1000; i++) {
// NOTE: We're using the newer arrow function syntax this time, but
// using the "function(x) { ..." syntax from the previous example
// here would not change the behavior shown.
adderFunctions[i] = x => x + i;
}
const add12 = adderFunctions[12];
// Yay! The behavior is as expected.
console.log(add12(8) === 20); // => true
// i's scope doesn't extend outside the for loop.
console.log(i); // => ReferenceError: i is not defined
Cette fois, i
est rebondi à chaque itération de la boucle for
. Chaque fonction conserve maintenant la valeur de i
au moment de sa création et adderFunctions
se comporte comme prévu.
Maintenant, en mélangeant les deux comportements, vous comprendrez probablement pourquoi il est déconseillé de mélanger les nouvelles variables let
et const
avec les anciennes var
dans le même script. Cela peut donner lieu à un code extrêmement confus.
const doubleAdderFunctions = [];
for (var i = 0; i < 1000; i++) {
const j = i;
doubleAdderFunctions[i] = x => x + i + j;
}
const add18 = doubleAdderFunctions[9];
const add24 = doubleAdderFunctions[12];
// It's not fun debugging situations like this, especially when the
// code is more complex than in this example.
console.log(add18(24) === 42); // => false
console.log(add24(18) === 42); // => false
console.log(add18(24) === add24(18)); // => false
console.log(add18(24) === 2018); // => false
console.log(add24(18) === 2018); // => false
console.log(add18(24) === 1033); // => true
console.log(add24(18) === 1030); // => true
Ne laissez pas cela vous arriver. Utilisez un linter.
NOTE: Ceci est un exemple pédagogique destiné à démontrer le comportement
var
/let
dans les boucles et avec des fermetures de fonctions faciles à comprendre. Ce serait un moyen terrible d'ajouter des chiffres. Mais la technique générale de capture de données dans des fermetures de fonctions anonymes peut être rencontrée dans le monde réel dans d'autres contextes. YMMV.
La différence est dans le scope des variables déclarées avec chacune.
En pratique, la différence de portée a plusieurs conséquences utiles:
let
ne sont visibles que dans leur bloc le plus proche englobant _ ({ ... }
).let
ne sont utilisables que dans les lignes de code qui apparaissent après la variable est déclarée (même si elles sont levées !).let
ne peuvent pas être redéclarées par un var
ou un let
suivant.let
ne sont pas ajoutées à l'objet global window
.let
sont faciles à utiliser avec fermetures (elles ne provoquent pas conditions de concurrence ).Les restrictions imposées par let
réduisent la visibilité des variables et augmentent la probabilité que des collisions de noms inattendues soient détectées plus tôt. Cela facilite le suivi et le raisonnement des variables, y compris leur accessibilité (aidant à récupérer la mémoire inutilisée).
Par conséquent, les variables let
sont moins susceptibles de poser des problèmes lorsqu'elles sont utilisées dans des programmes volumineux ou lorsque des cadres développés indépendamment sont combinés de manière nouvelle et inattendue.
var
peut toujours être utile si vous êtes certain de vouloir l'effet de liaison unique lorsque vous utilisez une fermeture dans une boucle (# 5) ou pour déclarer des variables globales visibles de l'extérieur dans votre code (# 4). L'utilisation de var
pour les exportations peut être remplacée si export
migre hors de l'espace du transpiler et dans la langue principale.
1. Aucune utilisation en dehors du bloc englobant le plus proche: Ce bloc de code génère une erreur de référence car la deuxième utilisation de x
se produit en dehors du bloc où il est déclaré avec let
:
{
let x = 1;
}
console.log(`x is ${x}`); // ReferenceError during parsing: "x is not defined".
En revanche, le même exemple avec var
fonctionne.
2. Aucune utilisation avant déclaration:
Ce bloc de code lancera une ReferenceError
avant que le code puisse être exécuté car x
est utilisé avant sa déclaration:
{
x = x + 1; // ReferenceError during parsing: "x is not defined".
let x;
console.log(`x is ${x}`); // Never runs.
}
En revanche, le même exemple avec var
analyse et s'exécute sans exception.
3. Pas de nouvelle déclaration: Le code suivant montre qu'une variable déclarée avec let
ne peut pas être redéclarée ultérieurement:
let x = 1;
let x = 2; // SyntaxError: Identifier 'x' has already been declared
4. Globals non attachés à window
:
var button = "I cause accidents because my name is too common.";
let link = "Though my name is common, I am harder to access from other JS files.";
console.log(link); // OK
console.log(window.link); // undefined (GOOD!)
console.log(window.button); // OK
5. Utilisation facile avec des fermetures: Les variables déclarées avec var
ne fonctionnent pas bien avec les fermetures à l'intérieur des boucles. Voici une boucle simple qui sort la séquence de valeurs que la variable i
a à différents moments dans le temps:
for (let i = 0; i < 5; i++) {
console.log(`i is ${i}`), 125/*ms*/);
}
Plus précisément, cela génère:
i is 0
i is 1
i is 2
i is 3
i is 4
En JavaScript, nous utilisons souvent des variables beaucoup plus tard que lors de leur création. Lorsque nous démontrons cela en retardant la sortie avec une fermeture passée à setTimeout
:
for (let i = 0; i < 5; i++) {
setTimeout(_ => console.log(`i is ${i}`), 125/*ms*/);
}
... la sortie reste inchangée tant que nous nous en tenons à let
. En revanche, si nous avions utilisé var i
à la place:
for (var i = 0; i < 5; i++) {
setTimeout(_ => console.log(`i is ${i}`), 125/*ms*/);
}
... la boucle génère inopinément "i is 5" cinq fois:
i is 5
i is 5
i is 5
i is 5
i is 5
Puissent les deux fonctions suivantes montrer la différence:
function varTest() {
var x = 31;
if (true) {
var x = 71; // Same variable!
console.log(x); // 71
}
console.log(x); // 71
}
function letTest() {
let x = 31;
if (true) {
let x = 71; // Different variable
console.log(x); // 71
}
console.log(x); // 31
}
let
est intéressant, car cela nous permet de faire quelque chose comme ceci:
(() => {
var count = 0;
for (let i = 0; i < 2; ++i) {
for (let i = 0; i < 2; ++i) {
for (let i = 0; i < 2; ++i) {
console.log(count++);
}
}
}
})();
Ce qui entraîne le comptage [0, 7].
Tandis que
(() => {
var count = 0;
for (var i = 0; i < 2; ++i) {
for (var i = 0; i < 2; ++i) {
for (var i = 0; i < 2; ++i) {
console.log(count++);
}
}
}
})();
Ne compte que [0, 1].
La principale différence entre var
et let
est que les variables déclarées avec var
sont function scoped . Alors que les fonctions déclarées avec let
sont block scoped . Par exemple:
function testVar () {
if(true) {
var foo = 'foo';
}
console.log(foo);
}
testVar();
// logs 'foo'
function testLet () {
if(true) {
let bar = 'bar';
}
console.log(bar);
}
testLet();
// reference error
// bar is scoped to the block of the if statement
variables avec var
:
Lorsque la première fonction testVar
est appelée la variable foo, déclarée avec var
, elle est toujours accessible en dehors de l'instruction if
. Cette variable foo
serait disponible partout dans le cadre de la testVar
fonction .
variables avec let
:
Lorsque la deuxième fonction testLet
est appelée barre de variable, déclarée avec let
, elle n'est accessible que dans l'instruction if
. Comme les variables déclarées avec let
sont block scoped (où un bloc est le code entre accolades, par exemple if{}
, for{}
, function{}
).
let
ne sont pas levées:Une autre différence entre var
et let
concerne les variables avec déclaré avec let
ne pas se hisser . Un exemple est le meilleur moyen d’illustrer ce comportement:
variables avec let
ne pas se hisser:
console.log(letVar);
let letVar = 10;
// referenceError, the variable doesn't get hoisted
variables avec var
do get hisse:
console.log(varVar);
var varVar = 10;
// logs undefined, the variable gets hoisted
let
ne s'attache pas à window
:Une variable déclarée avec let
dans la portée globale (qui est un code qui n'est pas dans une fonction) n'est pas ajoutée en tant que propriété sur l'objet global window
. Par exemple (ce code est dans la portée globale):
var bar = 5;
let foo = 10;
console.log(bar); // logs 5
console.log(foo); // logs 10
console.log(window.bar);
// logs 5, variable added to window object
console.log(window.foo);
// logs undefined, variable not added to window object
Dans quels cas
let
devrait-il être utilisé survar
?
Utilisez let
sur var
chaque fois que vous le pouvez, car la portée est plus précise. Cela réduit les conflits de noms potentiels pouvant survenir lors du traitement d'un grand nombre de variables. var
peut être utilisé lorsque vous souhaitez qu'une variable globale soit explicitement sur l'objet window
(réfléchissez toujours si cela est vraiment nécessaire).
Il semble également que, au moins dans Visual Studio 2015, TypeScript 1.5, "var" autorise plusieurs déclarations du même nom de variable dans un bloc et "let" ne le permette pas.
Cela ne générera pas d'erreur de compilation:
var x = 1;
var x = 2;
Cette volonté:
let x = 1;
let x = 2;
var
est une variable de portée globale (pouvant être levée).
let
et const
est une étendue de bloc.
test.js
{
let l = 'let';
const c = 'const';
var v = 'var';
v2 = 'var 2';
}
console.log(v, this.v);
console.log(v2, this.v2);
console.log(l); // ReferenceError: l is not defined
console.log(c); // ReferenceError: c is not defined
Lors de l'utilisation de let
Le mot clé let
attache la déclaration de variable à la portée de n'importe quel bloc (généralement une paire { .. }
) dans laquelle elle est contenue. En d'autres termes, let
pirate implicitement la portée de la déclaration d'une variable.
Les variables let
ne sont pas accessibles dans l'objet window
car elles ne peuvent pas être accessibles globalement.
function a(){
{ // this is the Max Scope for let variable
let x = 12;
}
console.log(x);
}
a(); // Uncaught ReferenceError: x is not defined
Lors de l'utilisation de var
var
et les variables dans ES5 ont des portées dans les fonctions, ce qui signifie que les variables sont valides dans la fonction et non en dehors de la fonction elle-même.
Les variables var
sont accessibles dans l'objet window
car elles ne peuvent pas être accessibles globalement.
function a(){ // this is the Max Scope for var variable
{
var x = 12;
}
console.log(x);
}
a(); // 12
Si vous voulez en savoir plus, continuez à lire ci-dessous
l’une des questions d’interview les plus connues sur la portée peut également suffire à l’utilisation exacte de let
et var
comme ci-dessous;
Si vous utilisez let
for (let i = 0; i < 10 ; i++) {
setTimeout(
function a() {
console.log(i); //print 0 to 9, that is literally AWW!!!
},
100 * i);
}
En effet, lorsque vous utilisez let
, la variable est étendue et a sa propre copie pour chaque itération de boucle.
Si vous utilisez var
for (var i = 0; i < 10 ; i++) {
setTimeout(
function a() {
console.log(i); //print 10 times 10
},
100 * i);
}
En effet, lorsque vous utilisez var
, la variable est étendue et a une copie partagée pour chaque itération de boucle.
Si j’ai bien lu les spécifications, alors let
heureusement peut aussi être utilisé pour éviter des fonctions invoquant elles-mêmes utilisées pour simuler des membres privés uniquement - un modèle de conception populaire qui diminue la lisibilité du code, complique le aucune protection de code réelle ou autre avantage - sauf peut-être satisfaire le désir de sémantique de quelqu'un, alors arrêtez de l'utiliser./rant}
var SomeConstructor;
{
let privateScope = {};
SomeConstructor = function SomeConstructor () {
this.someProperty = "foo";
privateScope.hiddenProperty = "bar";
}
SomeConstructor.prototype.showPublic = function () {
console.log(this.someProperty); // foo
}
SomeConstructor.prototype.showPrivate = function () {
console.log(privateScope.hiddenProperty); // bar
}
}
var myInstance = new SomeConstructor();
myInstance.showPublic();
myInstance.showPrivate();
console.log(privateScope.hiddenProperty); // error
Voir ' Emulation d'interfaces privées '
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"
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 est une partie de es6. Ces fonctions expliqueront la différence de manière simple.
function varTest() {
var x = 1;
if (true) {
var x = 2; // same variable!
console.log(x); // 2
}
console.log(x); // 2
}
function letTest() {
let x = 1;
if (true) {
let x = 2; // different variable
console.log(x); // 2
}
console.log(x); // 1
}
Auparavant, il n’existait que deux champs d’application en JavaScript, à savoir fonctionnel et global. Avec le mot clé 'let
', JavaScript a maintenant introduit les variables block-level
.
Pour bien comprendre le mot clé 'let', ES6: Le mot clé 'let' permettant de déclarer une variable en JavaScript vous aidera.
Cet article définit clairement la différence entre var, let et const
const
indique que l’identificateur ne sera pas réaffecté.
let
, indique que la variable peut être réaffectée, telle qu'un compteur dans une boucle, ou un échange de valeur dans un algorithme. Il signale également que la variable ne sera utilisée que dans le bloc dans lequel elle est définie, qui n'est pas toujours la totalité de la fonction contenant.
var
est maintenant le signal le plus faible disponible lorsque vous définissez une variable en JavaScript. La variable peut ou non être réaffectée, et le variable peut ou peut ne pas être utilisé pour une fonction entière, ou simplement pour le but d'un bloc ou d'une boucle.
https://medium.com/javascript-scene/javascript-es6-var-let-or-const-ba58b8dcde75#.esmkpbg9b
Maintenant, je pense que les variables sont mieux ciblées sur un bloc d'instructions utilisant let
:
function printnums()
{
// i is not accessible here
for(let i = 0; i <10; i+=)
{
console.log(i);
}
// i is not accessible here
// j is accessible here
for(var j = 0; j <10; j++)
{
console.log(j);
}
// j is accessible here
}
Je pense que les gens vont commencer à utiliser let here after afin d'avoir une portée similaire à JavaScript, à l'instar d'autres langages, Java, C #, etc.
Les personnes qui ne comprenaient pas bien la portée de JavaScript avaient l'habitude de faire l'erreur plus tôt.
Le levage n'est pas pris en charge avec let
.
Avec cette approche, les erreurs présentes dans JavaScript sont supprimées.
Reportez-vous à ES6 In Depth: let et const pour mieux le comprendre.
laissez vs var. Tout tourne autour de scope .
Les variables var sont globales et sont accessibles pratiquement partout, alors que les variables ne sont pas globales et n'existent que jusqu'à ce qu'une parenthèse fermante les tue.
Voir mon exemple ci-dessous et notez comment la variable lion (let) agit différemment dans les deux consoles.logs; il devient hors de portée dans le 2nd console.log.
var cat = "cat";
let dog = "dog";
var animals = () => {
var giraffe = "giraffe";
let lion = "lion";
console.log(cat); //will print 'cat'.
console.log(dog); //will print 'dog', because dog was declared outside this function (like var cat).
console.log(giraffe); //will print 'giraffe'.
console.log(lion); //will print 'lion', as lion is within scope.
}
console.log(giraffe); //will print 'giraffe', as giraffe is a global variable (var).
console.log(lion); //will print UNDEFINED, as lion is a 'let' variable and is now out of scope.
Comme mentionné ci-dessus:
La différence est la portée.
var
est affecté au fonction bloc le plus proche etlet
est associé au bloc englobant le plus proche, lequel peut être plus petit qu'un bloc de fonction. Les deux sont globaux si en dehors de block.Lets un exemple:
Exemple 1:
Dans mes deux exemples, j'ai une fonction myfunc
. myfunc
contient une variable myvar
égale à 10. Dans mon premier exemple, je vérifie si myvar
est égal à 10 (myvar==10
). Si oui, j’ai déclaré une variable myvar
(maintenant j’ai deux variables myvar) en utilisant le mot clé var
et lui attribue une nouvelle valeur (20). Dans la ligne suivante, j'imprime sa valeur sur ma console. Après le bloc conditionnel, j'imprime à nouveau la valeur myvar
sur ma console. Si vous regardez le résultat de myfunc
, myvar
a une valeur égale à 20.
Exemple2: Dans mon deuxième exemple, au lieu d'utiliser le mot clé var
dans mon bloc conditionnel, je déclare myvar
à l'aide du mot clé let
. Maintenant, lorsque j'appelle myfunc
, j'obtiens deux sorties différentes: myvar=20
et myvar=10
.
La différence est donc très simple, c'est-à-dire sa portée.
Regardez cette image, j'ai créé un exemple très simple pour la démonstration des variables const
et let
. Comme vous pouvez le constater, lorsque vous essayez de modifier la variable const
, vous obtenez le message d'erreur (Essayer de remplacer le nom 'qui est constant'), mais jetez un coup d'œil à la variable let
...
D'abord, nous déclarons let age = 33
, et plus tard, nous affectons une autre valeur age = 34;
, ce qui est correct. Nous n'avons pas d'erreur lorsque nous essayons de modifier la variable let
.
Je souhaite lier ces mots-clés au contexte d'exécution, car le contexte d'exécution est important dans tout cela. Le contexte d'exécution comporte deux phases: une phase de création et une phase d'exécution. De plus, chaque contexte d'exécution comporte un environnement variable et un environnement externe (son environnement lexical).
Au cours de la phase de création d’un contexte d’exécution, var, let et const conservent toujours sa variable en mémoire avec une valeur non définie dans l’environnement de variable du contexte d’exécution donné. La différence est dans la phase d'exécution. Si vous utilisez la référence d'une variable définie avec var avant qu'une valeur ne lui soit affectée, elle sera simplement indéfinie. Aucune exception ne sera levée.
Cependant, vous ne pouvez pas référencer la variable déclarée avec let ou const tant qu'elle n'a pas été déclarée. Si vous essayez de l'utiliser avant sa déclaration, une exception sera générée lors de la phase d'exécution du contexte d'exécution. Maintenant, la variable sera toujours en mémoire, grâce à la phase de création du contexte d'exécution, mais le moteur ne vous permettra pas de l'utiliser:
function a(){
b;
let b;
}
a();
> Uncaught ReferenceError: b is not defined
Avec une variable définie avec var, si le moteur ne peut pas la trouver dans l'environnement variable du contexte d'exécution actuel, il remontera la chaîne de la portée (environnement externe) et vérifiera l'environnement variable de l'environnement extérieur pour la variable. S'il ne peut pas le trouver, il continuera à chercher dans la chaîne Scope. Ce n'est pas le cas avec let et const.
La deuxième caractéristique de let est-il introduit la portée du bloc. Les blocs sont définis par des accolades. Les exemples incluent les blocs fonction, if block, for block, etc. Lorsque vous déclarez une variable avec let inside, la variable est uniquement disponible à l'intérieur du bloc. En fait, chaque fois que le bloc est exécuté, par exemple dans une boucle for, il crée une nouvelle variable en mémoire.
ES6 introduit également le mot-clé const pour la déclaration de variables. const est également bloqué. La différence entre let et const réside dans le fait que les variables const doivent être déclarées à l'aide d'un initialiseur, sinon cela générera une erreur.
Enfin, en ce qui concerne le contexte d’exécution, les variables définies avec var seront attachées à l’objet 'this'. Dans le contexte d'exécution global, il s'agira de l'objet window dans les navigateurs. Ce n'est pas le cas pour let ou const.
Je pense que les termes et la plupart des exemples sont un peu accablants. Le problème principal que j’ai eu personnellement avec la différence est de comprendre ce qu’est un "blocage". À un moment donné, j’ai réalisé qu’un bloc serait constitué de toute accolade, à l’exception de la déclaration IF
. un crochet ouvrant {
d'une fonction ou d'une boucle définira un nouveau bloc; tout ce qui est défini avec let
dedans ne sera pas disponible après le crochet fermant }
de la même chose (fonction ou boucle); Dans cet esprit, il était plus facile de comprendre:
let msg = "Hello World";
function doWork() { // msg will be available since it was defined above this opening bracket!
let friends = 0;
console.log(msg);
// with VAR though:
for (var iCount2 = 0; iCount2 < 5; iCount2++) {} // iCount2 will be available after this closing bracket!
console.log(iCount2);
for (let iCount1 = 0; iCount1 < 5; iCount1++) {} // iCount1 will not be available behind this closing bracket, it will return undefined
console.log(iCount1);
} // friends will no be available after this closing bracket!
doWork();
console.log(friends);
Étant donné que j'essaie actuellement de comprendre en profondeur le langage JavaScript, je partagerai ma brève recherche, qui contient quelques-uns des excellents éléments déjà discutés, ainsi que d'autres détails dans une perspective différente.
Comprendre la différence entre var et let peut être plus facile si nous comprenons la différence entre fonction et block scope .
Considérons les cas suivants:
(function timer() {
for(var i = 0; i <= 5; i++) {
setTimeout(function notime() { console.log(i); }, i * 1000);
}
})();
Stack VariableEnvironment //one VariablEnvironment for timer();
// when the timer is out - the value will be the same value for each call
5. [setTimeout, i] [i=5]
4. [setTimeout, i]
3. [setTimeout, i]
2. [setTimeout, i]
1. [setTimeout, i]
0. [setTimeout, i]
####################
(function timer() {
for (let i = 0; i <= 5; i++) {
setTimeout(function notime() { console.log(i); }, i * 1000);
}
})();
Stack LexicalEnvironment - each iteration has a new lexical environment
5. [setTimeout, i] [i=5]
LexicalEnvironment
4. [setTimeout, i] [i=4]
LexicalEnvironment
3. [setTimeout, i] [i=3]
LexicalEnvironment
2. [setTimeout, i] [i=2]
LexicalEnvironment
1. [setTimeout, i] [i=1]
LexicalEnvironment
0. [setTimeout, i] [i=0]
lorsque timer()
est appelé, un ExecutionContext est créé et contient à la fois le VariableEnvironment et tous les LexicalEnvironments correspondant à chaque itération.
Et un exemple plus simple
Portée de la fonction
function test() {
for(var z = 0; z < 69; z++) {
//todo
}
//z is visible outside the loop
}
Portée du bloc
function test() {
for(let z = 0; z < 69; z++) {
//todo
}
//z is not defined :(
}