@thefourtheye está correto ao dizer que essas variáveis não podem ser acessadas antes de serem declaradas. No entanto, é um pouco mais complicado que isso.
As variáveis são declaradas com letou constnão içadas? O que realmente está acontecendo aqui?
Todas as declarações ( var, let, const, function, function*, class) são "içada" em JavaScript. Isso significa que se um nome for declarado em um escopo, nesse escopo, o identificador sempre fará referência a essa variável específica:
x = "global";
// function scope:
(function() {
x; // not "global"
var/let/… x;
}());
// block scope (not for `var`s):
{
x; // not "global"
let/const/… x;
}
Isso vale para os escopos de função e bloco 1 .
A diferença entre var/ function/ function*declarações e let/ const/ classdeclarações é a inicialização .
Os primeiros são inicializados com undefinedou a função (gerador) logo que a ligação é criada na parte superior do escopo. As variáveis declaradas lexicamente, no entanto, não são inicializadas . Isso significa que uma ReferenceErrorexceção é lançada quando você tenta acessá-la. Ele só será inicializado quando a instrução let/ const/ classfor avaliada, tudo antes (acima) que é chamado de zona morta temporal .
x = y = "global";
(function() {
x; // undefined
y; // Reference error: y is not defined
var x = "local";
let y = "local";
}());
Observe que uma let y;instrução inicializa a variável com undefinedlike let y = undefined;.
A zona morta temporal não é um local sintático, mas o tempo entre a criação da variável (escopo) e a inicialização. Não é um erro referenciar a variável no código acima da declaração, desde que esse código não seja executado (por exemplo, um corpo de função ou simplesmente código morto), e será lançada uma exceção se você acessar a variável antes da inicialização, mesmo que o acesso código está abaixo da declaração (por exemplo, em uma declaração de função içada que é chamada muito cedo).
Existe alguma diferença entre lete constneste assunto?
Não, eles funcionam da mesma forma que o içamento é considerado. A única diferença entre eles é que uma constformiga deve ser e só pode ser atribuída na parte inicializadora da declaração ( const one = 1;tanto as const one;reatribuições quanto as posteriores one = 2são inválidas).
1: as vardeclarações ainda estão funcionando apenas no nível da função, é claro
let foo = () => bar; let bar = 'bar'; foo();ilustra todas as declarações são içadas efeito ainda melhor, porque não é óbvio devido à zona morta temporal.