Basicamente, toda definição em JavaScript é "hoisted" no topo de
seu escopo. O que quer dizer que quando usamos um
var foo = "bar"
o compilador JavaScript
vai mover o var foo;
no topo da função e
a definição do foo = "bar"
ira ficar
onde foi definida.
Considere o seguinte código:
fnExpression(); // => throw TypError!
var fnExpression = function() {
return "Im a expression assigned to a variable";
}
fnExpression(); // => "Im a expression assigned to a variable"
fnStatement(); // => "Im a statement with name"
fuction fnStatement() {
return "Im a statement with name";
}
fnStatement(); // => "Im a statement with name"
var scope = "global";
function fn() {
return scope;
var scope = "local";
}
fn(); // => undefined
Importante ressaltarmos também que uma expressão é
diferente de um statement, basicamente, no exemplo acima,
uma expressão é uma declaração com var fnExpression = function () {...}
,
enquanto um statement é fuction fnStatement() { ... }
).
Expressōes são "hoisted" no topo de seu escopo, mas não a sua inicialização,
logo no exemplo de var fnExpression = function () {...}
,
a var fnExpression
vai para o topo do escopo mas não
a sua inicialização, daí quando tentamos usar a função tomamos um
TypeError
, por outro lado, statements são
hoisted por inteiro e por isso o uso da fnStatement()
funciona antes de sua definição.
Para ter uma visualização melhor, é assim que esse código fica do ponto de vista do compilador:
var fnExpression, scope;
function fnStatement() {
return "Im a statement with name";
}
function fn() {
var scope;
return scope;
scope = "local";
}
fnExpression();
fnExpression = function() {
return "Im a expression assigned to a variable";
}
fnExpression();
fnStatement();
fnStatement();
scope = "global";
fn();