tl; dr Se você não estiver ligando para nada até que tudo carregue, você deve ficar bem.
Editar: para uma visão geral que também cobre algumas declarações ES6 ( let
, const
): https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Scope_Cheatsheet
Este comportamento estranho depende de
- Como você define as funções e
- Quando você liga para eles.
Aqui estão alguns exemplos.
bar(); //This won't throw an error
function bar() {}
foo(); //This will throw an error
var foo = function() {}
bar();
function bar() {
foo(); //This will throw an error
}
var foo = function() {}
bar();
function bar() {
foo(); //This _won't_ throw an error
}
function foo() {}
function bar() {
foo(); //no error
}
var foo = function() {}
bar();
Isso ocorre por causa de algo chamado içamento !
Existem duas maneiras de definir funções: declaração de função e expressão de função . A diferença é irritante e minuciosa, então vamos apenas dizer uma coisa um pouco errada: se você está escrevendo como function name() {}
, é uma declaração , e quando você escreve como var name = function() {}
(ou uma função anônima atribuída a um retorno, coisas assim), é uma expressão de função .
Primeiro, vamos ver como as variáveis são tratadas:
var foo = 42;
//the interpreter turns it into this:
var foo;
foo = 42;
Agora, como as declarações de função são tratadas:
var foo = 42;
function bar() {}
//turns into
var foo; //Insanity! It's now at the top
function bar() {}
foo = 42;
As var
declarações "jogam" a criação de foo
para o topo, mas ainda não atribuem o valor a ela. A declaração da função vem a seguir na linha e, finalmente, um valor é atribuído foo
.
E quanto a isso?
bar();
var foo = 42;
function bar() {}
//=>
var foo;
function bar() {}
bar();
foo = 42;
Apenas a declaração de foo
é movida para o topo. A atribuição vem somente após a chamada para bar
ser feita, onde estava antes de ocorrer todo o içamento.
E, finalmente, para concisão:
bar();
function bar() {}
//turns to
function bar() {}
bar();
Agora, e quanto às expressões de função ?
var foo = function() {}
foo();
//=>
var foo;
foo = function() {}
foo();
Assim como as variáveis regulares, primeiro foo
é declarado no ponto mais alto do escopo e, em seguida, é atribuído um valor.
Vamos ver por que o segundo exemplo gera um erro.
bar();
function bar() {
foo();
}
var foo = function() {}
//=>
var foo;
function bar() {
foo();
}
bar();
foo = function() {}
Como vimos antes, apenas a criação de foo
é içada, a atribuição vem onde apareceu no código "original" (não içada). Quando bar
é chamado, é antes de foo
ser atribuído um valor, então foo === undefined
. Agora, no corpo da função de bar
, é como se você estivesse fazendo undefined()
, o que gera um erro.