Comecei recentemente uma série para entendermos hoisting e escopo no ES2015. Se você não viu, clique aqui. Na primeira parte, falamos sobre escopo, e a ideia hoje é falar sobre hoisting. Vamos lá?
O que é Hoisting?
Hoisting: Levante (algo) por meio de cordas e polias. Sinônimos: levantar, levantar-se, elevador, transportar-se, erguer-se, subir, suba, guincho para cima, puxar para cima, elevar.
Em tempo de execução, todas as variáveis e declarações de funções são movidas para o início de cada função (seu próprio escopo), independentemente de onde eles são declarados – isso é conhecido como elevação (hoisting). Dito isso, é uma boa prática declarar todas as variáveis juntas na primeira linha, a fim de evitar falsas expectativas em relação a uma variável que foi declarada depois, mas que acabou recebendo um valor antes.
No entanto, somente a declaração será hoisted (elevada). Se a variável é também inicializada, o valor no topo do escopo será inicialmente configurado para undefined.
JavaScript Hoisting
Vamos vê-lo em ação:
(function() { var x = 'Vamos ver e entender '; ... // linhas de código ... var y = 'como nosso código '; ... // Mais algumas linhas de código ... var z = 'é interpretado e executado'; ... // Centenas de linhas de código ...
Que é interpretado e executado:
(function() { var x, y, z; // variáveis declaradas x = 'Vamos ver e entender '; // inicializado ... // linhas de código ... y = 'como nosso código '; // inicializado ... // Mais algumas linhas de código ... z = 'é interpretado e executado'; // inicializado
E por que eu devo me importar?
var text = "Javascript Roots !!!"; (function () { console.log("The value of variable: " + text); })();
O código acima está todo ok até o momento. Vamos fazer algumas modificações.
var text = "Javascript Roots !!!"; (function () { console.log("The value of variable: " + text); var text = "I love Javascript !!!" console.log("The new value of varible: " + text); })();
O primeiro console vai te retornar The value of variable: undefined e o segundo, The new value of varible: I love Javascript!!! Para muitos, o valor undefined é bem estranho, principalmente para desenvolvedores C (e sua família), além dos novos com JavaScript. Mas vamos entender o porquê disso:
var text = “Javascript Roots !!!”; (function () { var text; // declaração console.log(“The value of variable: “ + text); text = “I love Javascript !!!” // inicializado console.log(“The new value of varible: “ + text); })();
Eu sei que é bem estranho, mas por padrão devemos adotar que toda declaração de variáveis fiquem no início do seu código, evitando bugs.
Function Hoisting
As funções também são elevadas (hoisted):
minhaFuncaoHoisting(); // Outputs: “Sim!” function minhaFuncaoHoisting() { console.log(“Sim!”); }
O interpretador de JavaScript permite que você use uma função antes de ser declarado no código-fonte.
No entanto, a função de elevação ocorre apenas para funções declaradas, e não para funções anônimas.
fnHoisting(); // Sim esta função é hoisting =D fnNotHoisting(); // TypeError: fnNotHoisting is not a function function fnHoisting() { console.log(“Sim esta função é elevada =D”); } var fnNotHoisting = function() { console.log(“Esta função não é elevada =/”); }
No exemplo de código acima, vemos a interação de dois tipos diferentes de hoisting. Nossa variável fnNotHoisting tem a sua declaração hoisting, mas não o seu valor, que é undefined. Funções anônimas não são hoisting.
E o que mudou no ES2015?
Bem, com o ES2015, uma das boas mudanças foi a chegada de variáveis com let e escopo. Essa novidade permite declarar variáveis limitadas no âmbito de um bloco. É o oposto do var, por declarar e sobrescrever variáveis no âmbito global de sua função envolvente.
O let vai fazer hoisting da variável no topo do bloco, ou seja, caso seja declarado novamente no mesmo contexto, a segunda declaração retornará um TypeError. E caso a variável definida com let seja referenciada antes da sua declaração, o erro será de referência.
Vamos ver um exemplo com let:
function helpMe() { var help = 'Me ajude, localização -> '; if(help) { var location = '-23.5193987,-46.1895406'; } var phrase = help + location; console.log(phrase); //Me ajude, localizaçã -> -23.5193987,-46.1895406 } helpMe(); function imHere() { let im = 'Eu estou aqui ->' if (im) { let here = '-23.5193987,-46.1895406'; } let phrase = im + here; console.log(phrase) //ReferenceError: here is no defined
No código acima, temos as funções helpMe() e imHere(). Na função helpMe, a variável location pode ser acessada fora do bloco if. Por isso, quando chamamos a variável phrase, é retornado o resultado:
Me ajude, localização -> -23.5193987,-46.1895406
Diferentemente, na função imHere, a variável here nos retorna:
ReferenceError: here is not defined.
Isso acontece porque ela está definida dentro do bloco if, podendo ser acessada somente nesse bloco.
Diferença entre var e let
Com var, é possível redeclarar a mesma variável, mas o mesmo não acontece com let. Vamos ver um exemplo:
var x = 'foo1'; let y = 'bar1'; var x = 'foo2'; let y = 'bar2'; // SyntaxError: Identifier 'y' has already been declared console.log(x); console.log(y)
Com var, podemos ler a variável mesmo que o código ainda não tenho sido inicializado. Com var, isso vai retornar undefined; com let, vai te retornar um erro. Veja a seguir:
console.log(x); var x = 'foo'; console.log(y); // ReferenceError: y is not defined let y = 'foo';
Outro algo novo que surgiu é a Const. Em ES6, uma const representa uma referência constante para um valor. Em outras palavras, o valor não está congelado, apenas a atribuição dele.
{ const ARR = [01, 02]; ARR.push(10); console.log(ARR); // [01,02,10] ARR = 11; // TypeError ARR[0] = 03; // valor não é imutável console.log(ARR); // [03,02,10] }
Algumas coisas para lembrar:
- let e const são escopadas aos fechamentos de bloco mais próximos;
- Quando usar const, use CAPITAL_CASING;
- “hoisting” de let e const varia da forma tradicional de “hoisting” de variáveis e funções. Ambos estão “hoistados”, mas não podem ser acessados antes das suas declarações.
- const deve ser definida na sua declaração.
Ficou alguma dúvida ou tem algum comentário? Aproveite os campos abaixo. Até a próxima!
***
Artigo publicado originalmente em http://www.concretesolutions.com.br/2016/09/13/hoisting-e-escopo-es2015-2/.