View on GitHub

Capacitacao-CEOS-2-Javascript

Closures

Existe um conteúdo que geralmente é cobrado em entrevistas de emprego em Javascript: closures.

Closures são um recurso de programação funcional, que quando aplicadas em Javascript, nos ajudam a escrever código que não suja o escopo global. Isto é, evita a criação de variáveis globais.

Closures dependem bastante da compreensão dos escopos, se você não tiver entendido bem o capítulo de escopos, recomendo reler antes de continuar esse capítulo. Porém, se você tiver compreendido bem, vamos continuar.

Quando criamos uma função, ela cria a “bolha” do escopo dela.

function foo() {
    let a = 1;
}

Qualquer código fora da função foo, não tem acesso ao escopo dela, portanto, não pode acessar a variável a.

Porém, se criarmos uma função dentro de foo, essa função poderá acessar o escopo de foo.

Então vamos criar uma função que incrementa e mostra a incrementado.

function foo() {
    let a = 1;

    function bar() {
        a++;
        console.log(a);
    }
}

bar pode acessar o escopo de foo, além de qualquer código em foo.

E é isso, temos a nossa primeira closure!

A closure é uma função interior que tem acesso a variáveis de uma função exterior, através das regras de acesso de variáveis no escopo!

Portanto, bar é a nossa closure, pois ela é uma função interna (está dentro de foo).

Mas nesse caso, ainda não ficou claro a utilidade, porque não estamos usando bar.

O interessante vem agora: podemos retornar a função bar da função foo:

function foo() {
    let a = 1;

    function bar() {
        a++;
        console.log(a);
    }

    return bar;
}

E como estamos retornando uma função, podemos guardar essa função retornada, e invocar ela no código exterior (que está no contexto do escopo global):

function foo() {
    let a = 1;

    function bar() {
        a++;
        console.log(a);
    }

    return bar;
}

let bar = foo();

bar(); // 2
bar(); // 3
bar(); // 4

O código acima pode ser extremamente “bugante” (e é mesmo!), porém, vamos analisar com calma:

A função bar tem acesso ao escopo de foo

Invocamos a função foo, que retorna a função bar

E guardamos essa função retornada na variável bar.

A parte confusa é que: a função foo já terminou sua execução, com o return.

Porém, como bar tem acesso ao escopo de foo, esse escopo continua acessível, porém, acessível agora apenas para a função bar.

Se não tiver entendido, releia novamente, com calma. É um pouco esquisito mesmo.

Porém, é isso. Geralmente closures tem esse formato, e geralmente nós escrevemos closures sem perceber, quando escrevemos código assincrono por exemplo. (Código assincrono será mais detalhado na apostila 4 - Programação Assincrona).

Esse exemplo pode ter parecido meio bobo, mas com closures conseguimos ter encapsulamento, que é um principio importante em desenvolvimento de software.

Elas permitem esconder detalhes de implementação do código que está invocando a função.

Por exemplo, quem estiver chamando bar não precisa saber que estamos usando a variável a para realizar os incrementos.

Quando chamamos bibliotecas externas em nosso código, pelo menos em Javascript, essas bibliotecas geralmente usam closures para realizar operações internas, expondo pra você apenas as funções e métodos que a gente precisa.

Para mais informações, você pode consultar a documentação da MDN.