Quando começamos a trabalhar, estudar, brincar ou qualquer outra relação com uma linguagem de programação é imprescindível sabermos como funciona alguns pontos, um desses pontos na minha opinião é a sua compilação/interpretação. Ao entender o que acontece nos bastidores das linguagens que usamos para desenvolver nossos programas evitamos bug’s e/ou conseguimos resolve-los de forma mais rápida. Nesse post explicarei um ponto do javaScript chamado Hoisting.

javascript_logo

HOISTING      

  Hoisting ou elevação é o nome dado a um comportamento no javaScript que faz com que todas as declarações, de variáveis ou de funções, sejam movidas para o inicio do escopo atual em tempo de execução. Veja o Exemplo 1:

[sourcecode language="javascript"]
//Exemplo 1
function conhecendoHoisting(){

  return x;

    function x(){

      return 5;

    }

}

var y = conhecendoHoisting();

y();
[/sourcecode]

No Exemplo 1, em um primeiro momento, poderíamos imaginar que a função conhecendoHoisting() retornaria undefined ocasionando um erro. Porém, não é isso que acontece. Antes de explicar, veja na Figura 1 o retorno da execução do Exemplo 1 utilizando o console do Google Chrome 39.0.2171.71:

[caption id="attachment_349" align="alignnone" width="653"]Figura 1 - Retorno do exemplo anterior. Figura 1 - Retorno do exemplo 1 usando o console do Chrome.[/caption]

Ao encontrar a função conhecendoHoisting() o compilador eleva para o topo do escopo tudo o que é declaração. E tudo o que é execução irá para o final do escopo de acordo com a ordem em que foi escrito. A ordem do escopo, de cima para baixo, fica assim:

  1. Declarações de variáveis;
  2. Declarações de funções; e
  3. Execuções.

Sabendo disso, pode-se dizer que o Exemplo 1 foi compilado da seguinte maneira:

[sourcecode language="javascript"]
function conhecendoHoisting(){

  function x(){

    return 5;

  }

return x;

}

var y = conhecendoHoisting();

y();
[/sourcecode]

Vejamos um outro exemplo:

[sourcecode language="javascript"]

//Exemplo 2
function segundoExemplo(){

function testeHoisting(){

return 1;

}

return testeHoisting;

function testeHoisting(){

return 2;

}

}

var y = segundoExemplo();

y();
[/sourcecode]

Veja na Figura 2 o retorno da execução do Exemplo 2:

[caption id="attachment_352" align="alignnone" width="300"]Figura 2 - Retorno da execução do exemplo 2 no console do Chrome. Figura 2 - Retorno da execução do exemplo 2 no console do Chrome.[/caption]

O que acontece no Exemplo 2 em partes é a mesma coisa que acontece no Exemplo 1. As declarações, nesse caso temos as duas funções, vão para o topo do escopo. A diferença aqui é que existem duas funções com o mesmo nome, como o compilador sabe qual deverá retornar? Nesse exemplo as duas funções não podem existir da forma que foram declaradas, não ocorrerá nenhum erro, mas quando o compilador encontrar a segunda declaração ele sobrescreverá a primeira. Sabendo disso, pode-se dizer que o código do Exemplo 2 foi compilado da seguinte maneira:

[sourcecode language="javascript"]

//Exemplo 2
function segundoExemplo(){
//esta função será sobrescrita
function testeHoisting(){

return 1;

}

//esta função sobrescreverá a função anterior que possui a mesma declaração
function testeHoisting(){

return 2;

}

return testeHoisting;

}

var y = segundoExemplo();

y();
[/sourcecode]

Para mostrar o ultimo exemplo entraremos em um novo tópico.

INICIALIZAÇÕES NÃO SÃO ELEVADAS

Anteriormente, nesse mesmo post, comentei que somente as declarações são elevadas. Portanto, uma inicialização não será elevada. Para entender isso, veja os snippet's 1 e 2:

[sourcecode language="javascript"]

//Snippet 1
function exemploInicializacao(){

function testeInicializao(){
//...
}
//Inicialização
var x = 1;
}
[/sourcecode]

[sourcecode language="javascript"]

//Snippet 2
function exemploInicializacao(){

function testeInicializao(){
//...
}
var x;
x = 1;
}
[/sourcecode]

O Snippet 1 não sofrerá alteração em sua compilação. Já o Snippet 2, será compilado da seguinte maneira:

[sourcecode language="javascript"]

//Snippet 2
function exemploInicializacao(){
var x;
function testeInicializao(){
//...
}

x = 1;
}
[/sourcecode]

Entendendo isso, vamos ver o que acontece com as function expression. Veja o Exemplo 3:

[sourcecode language="javascript"]

//Exemplo 3
function terceiroExemplo(){

return x;

var x = function(){

return 1;

}

}

var y = terceiroExemplo();

y();
[/sourcecode]

O Exemplo 3 tem certa semelhança com o Exemplo 1. Entretanto, nesse caso estamos usando uma function expression. Como vimos anteriormente, somente declarações são elevadas, sendo assim, na execução do Exemplo 3 teremos um erro. Antes de ver como será compilado, veja sua execução:

[caption id="attachment_354" align="alignnone" width="646"]Figura 3 - Retorno da execução do Exemplo 3 usando o console do Chrome. Figura 3 - Retorno da execução do Exemplo 3 usando o console do Chrome.[/caption]

Agora veja como será compilado:

[sourcecode language="javascript"]

//Exemplo 3
function terceiroExemplo(){

var x;

return x;

x = function(){

return 1;

}

}

var y = terceiroExemplo();

y();
[/sourcecode]

Analisando o Exemplo 3, podemos verificar que a atribuição da function para a variável x será ignorada, uma vez que a função terceiroExemplo() será finalizada na linha return x; e desse modo a variável x terá o valor de undefined no momento do retorno.

Bom, espero ter conseguido ser claro nos meus exemplos sobre Hoisting.

Até o próximo post!.

Referencias

http://www.w3schools.com/js/js_hoisting.asp

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/function