Esse fenômeno é conhecido como: JavaScript Variable Hoisting .
Em nenhum momento você acessa a variável global em sua função; você está sempre acessando a value
variável local .
Seu código é equivalente ao seguinte:
var value = 10;
function test() {
var value;
console.log(value);
value = 20;
console.log(value);
}
test();
Ainda está surpreso com o que você está recebendo undefined
?
Explicação:
Isso é algo que todo programador de JavaScript se depara mais cedo ou mais tarde. Simplificando, quaisquer variáveis que você declarar são sempre içadas para o topo de seu fechamento local. Portanto, mesmo que você tenha declarado sua variável após a primeira console.log
chamada, ela ainda é considerada como se você a tivesse declarado antes disso.
No entanto, apenas a parte da declaração está sendo içada; a atribuição, por outro lado, não é.
Portanto, quando você chamou pela primeira vez console.log(value)
, estava referenciando sua variável declarada localmente, que ainda não tem nada atribuído a ela; daí undefined
.
Aqui está outro exemplo :
var test = 'start';
function end() {
test = 'end';
var test = 'local';
}
end();
alert(test);
O que você acha que isso alertará? Não, não apenas continue lendo, pense sobre isso. Qual é o valor de test
?
Se você disse qualquer coisa diferente start
, você estava errado. O código acima é equivalente a este:
var test = 'start';
function end() {
var test;
test = 'end';
test = 'local';
}
end();
alert(test);
para que a variável global nunca seja afetada.
Como você pode ver, não importa onde você coloque sua declaração de variável, ela sempre é içada para o topo de seu fechamento local.
Nota:
Isso também se aplica a funções.
Considere esta parte do código :
test("Won't work!");
test = function(text) { alert(text); }
o que dará a você um erro de referência:
ReferenceError não capturado: teste não definido
Isso confunde muitos desenvolvedores, pois este código funciona bem:
test("Works!");
function test(text) { alert(text); }
A razão para isso, conforme declarado, é porque a peça de atribuição não é içada. Portanto, no primeiro exemplo, quando test("Won't work!")
foi executado, a test
variável já foi declarada, mas ainda não teve a função atribuída a ela.
No segundo exemplo, não estamos usando atribuição de variável. Em vez disso, estamos usando a sintaxe de declaração de função apropriada, o que faz com que a função seja completamente içada.
Ben Cherry escreveu um excelente artigo sobre isso, apropriadamente intitulado JavaScript Scoping and Hoisting .
Leia-o. Ele lhe dará a imagem completa com todos os detalhes.