Opa galera, beleza?
Algumas coisas podem nos trazer certos inconvenientes, como por exemplo comer melância e na sequência tomar leite. Essas coisas nos fazem refletir, por que deus fez desse jeito?
No javascript temos um caso desse tipo: o hoisting. Talvez alguns de vocês ja tenham passado por algum erro gerado por ele e consertaram sem entender o por que aquilo aconteceu.
Vamos entender primeiro o que é isso:
Hoisting is JavaScript’s default behavior of moving declarations to the top.
Segundo o MDN hoisting é o comportamento de mover as declarações para o topo. Ta! mas e a treta das galáxias aquela?
É exatamente esse comportamento que pode nos trazer dor de cabeça, vamos para o código.
var test = "Test"; (function() { console.log(test); // >>> Test })();
Nesse trecho do código eu declarei uma variável chamada test e dei e atribui a ela a string “Test”, a seguir eu criei uma self-invoked anonymous function que tem somente um console.log que vai printar o valor da variável test no console. Nesse bloco de código temos dois escopos: o do nosso arquivo principal e o da nossa função.
Agora vamos adicionar mais uma coisa no nosso código e vamos ver o que vai acontecer:
var test = "Test"; (function() { console.log(test); // >>> undefined var test = "Denovo"; })();
Agora apenas declaramos uma variável com o mesmo nome dentro do escopo da função global e “pum”o log do console printou undefined.

why?
Por quê? vocês não levaram a frase do MDN a sério né? Como foi citado, o hoisting é o processo de mover as declarações para o topo. Que topo? o topo do escopo.
Ou seja, ele separa nossas declarações em duas etapas: declaração e inicialização. Para exemplificar melhor, vamos ver como o js interpreta o nosso código:
var test; test = "Test"; (function() { var test; console.log(test); test = "Denovo"; })();
Se analisarmos sem muito esforço já dá pra ver que ele declara nossas variáveis no início do escopo e, no nosso, caso quando o log do console vai ser printado ele está undefined ainda.
E isso também serve para um caso bem comum que é a atribuição de funções para variáveis. Vamos a mais um exemplo:
funcaoUm(); function funcaoUm() { console.log("Funcao um"); // >> Funcao um } funcaoDois(); var funcaoDois = function() { // Erro console.log("Funcao dois"); };
Nesse exemplo o log da função “um” vai ser printado normalmente, mesmo ela sendo chamada antes da declaração da função; já a função “dois” vai gerar um erro e alertar que a função não existe por que ela foi atribuída para uma variável e foi chamada antes de ser inicializada.
Bom galera, era isso. Espero que essa dica ajude vocês!
Um grande abraço.