Je joue avec ES6 depuis un moment et j'ai remarqué que, bien que les variables déclarées avec var
soient levées comme prévu ...
console.log(typeof name); // undefined
var name = "John";
... les variables déclarées avec let
ou const
semblent rencontrer quelques problèmes de levage:
console.log(typeof name); // ReferenceError
let name = "John";
et
console.log(typeof name); // ReferenceError
const name = "John";
Cela signifie-t-il que les variables déclarées avec let
ou const
ne sont pas levées? Qu'est-ce qui se passe vraiment ici? Existe-t-il une différence entre let
et const
en la matière?
@thefourtheye a raison de dire que ces variables inaccessibles avant d'être déclarées. Cependant, c'est un peu plus compliqué que cela.
Les variables déclarées avec
let
ouconst
ne sont-elles pas levées? Qu'est-ce qui se passe vraiment ici?
Toutes les déclarations (var
, let
, const
, function
, function*
, class
) sont "hissés" en JavaScript. Cela signifie que si un nom est déclaré dans une étendue, l'identifiant référencera toujours cette variable particulière:
x = "global";
// function scope:
(function() {
x; // not "global"
var/let/… x;
}());
// block scope (not for `var`s):
{
x; // not "global"
let/const/… x;
}
Ceci est vrai à la fois pour les portées de fonction et de bloc1.
La différence entre var
/function
/function*
déclarations et let
/const
/class
déclarations est le initialisation .
Les premiers sont initialisés avec undefined
ou la fonction (générateur) dès que la liaison est créée en haut de la portée. Les variables déclarées lexicalement restent cependant non initialisées. Cela signifie qu'une exception ReferenceError
est générée lorsque vous essayez d'y accéder. Il ne sera initialisé que lorsque l'instruction let
/const
/class
sera évaluée, tout ce qui précède (ci-dessus) est appelé la zone morte temporelle .
x = y = "global";
(function() {
x; // undefined
y; // Reference error: y is not defined
var x = "local";
let y = "local";
}());
Notez qu'une instruction let y;
initialise la variable avec undefined
comme let y = undefined;
.
La zone morte temporelle n'est pas un emplacement syntaxique, mais plutôt le temps entre la création de la variable (scope) et l’initialisation. Ce n’est pas une erreur de référencer la variable dans le code au-dessus de la déclaration tant que ce code n’est pas exécuté (par exemple, un corps de fonction ou simplement un code mort), et une exception sera levée si vous accédez à la variable avant l’initialisation, même si Le code est en dessous de la déclaration (par exemple dans une déclaration de fonction levée appelée trop tôt).
Existe-t-il une différence entre
let
etconst
en la matière?
Non, ils fonctionnent de la même manière en ce qui concerne le levage. La seule différence entre eux est qu'un const
ant doit être et ne peut être affecté que dans la partie initialisation de la déclaration (const one = 1;
, const one;
et des réassignements ultérieurs tels que one = 2
sont invalide).
1: var
les déclarations ne fonctionnent toujours qu'au niveau de la fonction, bien sûr
Citant la spécification de la spécification ECMAScript 6 (ECMAScript 2015), let
et const
déclarations section,
Les variables sont créées lorsque leur environnement lexical contenant est instancié, mais il est impossible d’accéder tant que la variable LexicalBinding n’est pas évaluée .
Donc, pour répondre à votre question, oui, let
et const
palan, mais vous ne pouvez pas y accéder avant que la déclaration proprement dite ne soit évaluée au moment de l'exécution.
ES6
introduit les variables Let
qui apparaissent avec block level scoping
. Jusqu'au ES5
nous n'avions pas block level scoping
, donc les variables déclarées à l'intérieur d'un bloc sont toujours hoisted
au niveau de la portée.
Fondamentalement, Scope
fait référence à l'endroit où, dans votre programme, vos variables sont visibles, ce qui détermine où vous êtes autorisé à utiliser des variables que vous avez déclarées. Dans ES5
nous avons global scope,function scope and try/catch scope
, avec ES6
, nous obtenons également la portée du niveau de bloc en utilisant Let.
var
, la fonction entière est connue à partir du moment où elle est définie.Lorsque vous définissez une variable avec l'instruction let
, elle n'est connue que dans le bloc défini.
function doSomething(arr){
//i is known here but undefined
//j is not known here
console.log(i);
console.log(j);
for(var i=0; i<arr.length; i++){
//i is known here
}
//i is known here
//j is not known here
console.log(i);
console.log(j);
for(let j=0; j<arr.length; j++){
//j is known here
}
//i is known here
//j is not known here
console.log(i);
console.log(j);
}
doSomething(["Thalaivar", "Vinoth", "Kabali", "Dinesh"]);
Si vous exécutez le code, vous constaterez que la variable j
n'est connue que dans loop
et non avant et après. Cependant, notre variable i
est connue dans le entire function
à partir du moment où elle est définie.
Il y a un autre grand avantage à utiliser let as it crée un nouvel environnement lexical et lie également une nouvelle valeur plutôt que de conserver une ancienne référence.
for(var i=1; i<6; i++){
setTimeout(function(){
console.log(i);
},1000)
}
for(let i=1; i<6; i++){
setTimeout(function(){
console.log(i);
},1000)
}
La première boucle for
affiche toujours la dernière valeur , avec let
elle crée une nouvelle portée et lie les nouvelles valeurs en nous imprimant 1, 2, 3, 4, 5
.
En venant de constants
, cela fonctionne fondamentalement comme let
, la seule différence est que leur valeur ne peut pas être modifiée. En constantes la mutation est autorisée mais la réaffectation est interdite.
const foo = {};
foo.bar = 42;
console.log(foo.bar); //works
const name = []
name.Push("Vinoth");
console.log(name); //works
const age = 100;
age = 20; //Throws Uncaught TypeError: Assignment to constant variable.
console.log(age);
Si une constante fait référence à une object
, elle fera toujours référence à la object
, mais la object
elle-même peut être modifiée (si elle est mutable). Si vous aimez avoir un object
immuable, vous pouvez utiliser Object.freeze([])
Dans ECMAScript 2015, let
et const
sont levés mais non initialisés. Référencer la variable dans le bloc avant la déclaration de variable a pour résultat un ReferenceError
car la variable est dans une "zone morte temporelle" à partir du début du bloc jusqu'à ce que la déclaration soit traitée.
console.log(x); // ReferenceError
let x = 3;