Concrete Logo
Hamburger button

Entendendo hoisting e escopo, o que mudou no ES2015 – Parte 1

  • Blog
  • 12 de Setembro de 2016
Share

*Este post foi originalmente publicado no Medium pessoal do autor. Confira aqui.

Alguns programadores que começam em Javascript sempre acabam passando por problemas para entender Hoisting e Escopo. Afinal, WTF man???

Vejamos o código abaixo:

Nele, declaramos name como uma variável global com o valor “Marquinho” e temos a chamada da função family() e neighborhood(). A diferença é que a função family tem como escopo IIFE e funciona mesmo sendo definida depois. Já neighborhood não é hoisted, apenas sua declaração.

Em JavaScript, todas as declarações de funções e variáveis são movidas para o topo de cada escopo, e isto chamamos de hoisting. Em tempo de execução, ao declarar sua variável e função, a mesma é sempre elevada ao topo.

Porém, somente sua declaração é hoisted, a sua inicialização não. Funções anônimas ou expressão de função também são hoisted e acontece a mesma coisa, por isso a função neighborhood, ao ser invocada na linha 4, nos retorna undefined.

Vamos entender como nosso código é interpretado:

Declaração e inicialização?

É muito importante entender a diferença entre declarar e inicializar uma variável em JavaScript.

Declaração

Inicialização

No ES5 temos dois escopos para as variáveis: escopo de função e global.

O que é Escopo?

Em ES5, as funções são nosso delimitador de escopo de fato para declaração de variáveis. Isso significa que blocos usuais de loops e estruturas condicionais (como if, for, while, switch e try) NÃO delimitam escopos, diferente de muitas outras linguagens como C, C++, Java e ES2015.

Portanto, esses blocos compartilham do mesmo escopo que a função que os contém. Dessa forma, pode ser perigoso declarar variáveis dentro de blocos, já que vai parecer que a variável pertence apenas ao bloco. Esse é um problema comum para programadores vindos de linguagens com escopos em blocos.

Como entrar em um escopo?

Temos quatro maneiras:

  • Definido pela linguagem: todo escopo possui o this e, caso seja uma função, também o arguments.
  • Declaração de uma variável: variáveis declaradas como var name.
  • Declaração de uma função: funções declaradas na forma function family() {}.
  • Parâmetros de uma função: caso uma função seja chamada na forma brother (name), podendo ser brother (name, mother, …), sendo name e mother entram no escopo da função.

Como poderia ficar nosso código:

No código acima ainda podemos acessar a varivel newVal fora do bloco do loop, bem como podemos criar um escopo dentro do loop em ES5 utilizando ‘IIFE’ (sobre esse assunto, recomento a leitura deste post, feito por meu amigo Pedro Araujo). Essa era nossa única maneira de se criar um escopo dentro de um bloco, mas com a vinda do ES2015 isto mudou.

Vamos ver se ficou claro:

E o que é this?

Aqui está uma das partes mais confusas do JavaScript. Como o this funciona? O que come? Onde vive?

Brincadeiras à parte, this é uma referência ao contexto no qual a função está sendo executada, ao objeto ao qual ela pertence. Em grande parte de outras linguagens o this é uma referência ao objeto atual instanciado. Contudo, para dar um nó na sua mente, em JavaScript o this vai depender de como sua função foi inicializada.

Algumas formas de chamar uma função:

  1. Diretamente
  2. Como um método
  3. Explicitamente aplicada
  4. Como construtor

Diretamente
Quando uma função é chamada diretamente, this fará referência ao contexto global, que no caso dos navegadores é o objeto window.

Como um método

São funções armazenadas dentro das propriedades de um objeto. Se uma função for chamada como um método de um objeto, então this, dentro dessa função, fará referência a esse objeto.

Explicitamente aplicada
Uma função pode ser aplicada explicitamente a qualquer objeto, e para isso utilizamos os métodos call ou apply. Saiba mais neste post aqui.

Os métodos call e apply nos permitem controlar o valor de this e assim definir a qual objeto ele fará referência. A diferença entre eles é a forma que recebem os parâmetros e também a velocidade de execução que pode variar de navegador para navegador.

Na função createPhrase faço referência ao objeto ‘myObject’. Com isso, consigo acessar os nós dele: this.phraseC que tem como valor Entendendo como funciona e this.phraseD que tem como valor Quando uma função é aplicada explicitamente.

Como um construtor
Quando uma função é usada como um construtor (usando a palavra-chave new), this fará referência ao novo objeto que está sendo construído:

E por hoje é só =) Amanhã eu volto para falar sobre Hoisting na segunda parte dessa série. Ficou alguma dúvida, tem alguma observação a fazer ou algum comentário? Fique à vontade nos campos abaixo. Até a próxima!