Master a Entrevista Javascript: O que é um Closure?

“Master the JavaScript Interview” é uma série de posts concebidos para preparar os candidatos para perguntas comuns que provavelmente encontrarão ao candidatarem-se a uma posição JavaScript de nível médio a sénior. Estas são perguntas que utilizo frequentemente em entrevistas reais.

Vou lançar a série com a pergunta de $40k. Se responder mal a esta pergunta, há uma boa hipótese de não ser contratado. Se for contratado, há uma boa hipótese de ser contratado como programador júnior, independentemente de há quanto tempo trabalha como programador de software. Em média, os programadores júnior recebem $40k/ano menos USD do que os engenheiros de software mais experientes.

Acabamentos são importantes porque controlam o que está e não está no âmbito de uma determinada função, juntamente com as variáveis que são partilhadas entre as funções dos irmãos no mesmo que contém o âmbito. Compreender como as variáveis e funções se relacionam entre si é fundamental para compreender o que se passa no seu código, tanto no estilo de programação funcional como no estilo de programação orientada para objectos.

A razão pela qual a falta desta pergunta é tão desvantajosa numa entrevista é que os mal-entendidos sobre como funcionam os encerramentos são uma bandeira vermelha bastante clara que pode revelar uma falta de experiência profunda, não apenas em JavaScript, mas em qualquer linguagem que dependa muito dos encerramentos (Haskell, C#, Python, etc…).

Codificar em JavaScript sem compreender os encerramentos é como tentar falar inglês sem compreender as regras gramaticais – pode ser capaz de transmitir as suas ideias, mas provavelmente um pouco embaraçoso.

Também será vulnerável a mal-entendidos quando estiver a tentar compreender o que outra pessoa escreveu.

Não só deve saber o que é um encerramento, como também deve saber porque é importante, e ser capaz de responder facilmente a vários possíveis casos de uso para encerramentos.

Os encerramentos são frequentemente utilizados em JavaScript para privacidade de dados de objectos, em manipuladores de eventos e funções de chamada de retorno, e em aplicações parciais, currying, e outros padrões de programação funcional.

Se não conseguir responder a esta pergunta, pode custar-lhe o trabalho, ou ~$40k/ano.

Estar preparado para um seguimento rápido: “Pode nomear dois usos comuns para encerramentos?”

O que é um Encerramento?

Um encerramento é a combinação de uma função agrupada (em anexo) com referências ao seu estado circundante (o ambiente lexical). Por outras palavras, um fecho dá-lhe acesso ao âmbito de uma função exterior a partir de uma função interior. No JavaScript, os fechos são criados cada vez que uma função é criada, no momento da criação da função.

Para usar um fecho, definir uma função dentro de outra função e expô-la. Para expor uma função, devolva-a ou passe-a para outra função.

A função interna terá acesso às variáveis no âmbito da função externa, mesmo depois de a função externa ter retornado.

Usar Fechamentos (Exemplos)

entre outras coisas, os fechamentos são normalmente usados para dar privacidade aos dados dos objectos. A privacidade dos dados é uma propriedade essencial que nos ajuda a programar para uma interface, não uma implementação. Este é um conceito importante que nos ajuda a construir software mais robusto porque os detalhes da implementação são mais susceptíveis de mudar de forma a quebrar os contratos de interface.

“Programar para uma interface, não para uma implementação”
Design Patterns: Elementos de Software Reutilizável Orientado a Objectos

Em JavaScript, os fechos são o mecanismo primário utilizado para permitir a privacidade dos dados. Quando se utilizam encerramentos para a privacidade de dados, as variáveis incluídas só estão no âmbito da função (externa) que contém os dados. Não é possível obter os dados a partir de um âmbito exterior, excepto através dos métodos privilegiados do objecto. Em JavaScript, qualquer método exposto definido dentro do âmbito do encerramento é privilegiado. Por exemplo:

Play with this in JSBin. (Não vê nenhum resultado? Copie e cole este HTML no painel HTML.)

No exemplo acima, o método `.get()` é definido dentro do âmbito de `getSecret()`, o que lhe dá acesso a quaisquer variáveis de `getSecret()`, e torna-o um método privilegiado. Neste caso, o parâmetro `secret`.

Objects não é a única forma de produzir privacidade de dados. Os encerramentos também podem ser utilizados para criar funções de estado cujos valores de retorno podem ser influenciados pelo seu estado interno, por exemplo:

const secret = msg => () => msg;

disponível no JSBin. (Não vê nenhuma saída? Copie e cole este HTML no painel HTML.)

Na programação funcional, os fechos são frequentemente utilizados para aplicação parcial & currying. Isto requer algumas definições:

Aplicação: O processo de aplicação de uma função aos seus argumentos de modo a produzir um valor de retorno.

Aplicação parcial: O processo de aplicação de uma função a alguns dos seus argumentos. A função parcialmente aplicada é devolvida para utilização posterior. A aplicação parcial fixa (aplica parcialmente a função a) um ou mais argumentos dentro da função devolvida, e a função devolvida toma os restantes parâmetros como argumentos para completar a aplicação da função.

Aplicação parcial tira partido do âmbito de fecho para fixar parâmetros. É possível escrever uma função genérica que aplicará parcialmente argumentos à função de destino. Terá a seguinte assinatura:

partialApply(targetFunction: Function, ...fixedArgs: Any) =>
functionWithFewerParams(...remainingArgs: Any)

Se precisar de ajuda para ler a assinatura acima, verifique Rtype: Leitura da Função Assinaturas.

Terá uma função que aceita qualquer número de argumentos, seguida de argumentos que queremos aplicar parcialmente à função, e retorna uma função que aceita os restantes argumentos.

Um exemplo ajudará. Digamos que tem uma função que acrescenta dois números:

const add = (a, b) => a + b;

Agora quer uma função que acrescenta 10 a qualquer número. Vamos chamar-lhe `add10()`. O resultado de “add10(5)`add10` deve ser `15`. A nossa função `partialApply()` pode fazer isso acontecer:

const add10 = partialApply(add, 10);
add10(5);

Neste exemplo, o argumento, `10` torna-se um parâmetro fixo lembrado dentro do `add10()` âmbito de fecho.

Vejamos um possível `partialApply()` implementação:

disponível no JSBin. (Não vê nenhuma saída? Copie e cole este HTML no painel HTML.)

Como pode ver, simplesmente devolve uma função que retém o acesso aos argumentos “fixedArgs” que foram passados para a “partialApply()` function.

Your Turn

Este post tem um post de vídeo companheiro e tarefas práticas para membros de EricElliottJS.com. Se já é membro, inscreva-se e pratique agora.

Se não é membro, inscreva-se hoje.

Explore a Série

  • O que é um Encerramento?
  • Qual é a diferença entre Classe e Herança Protótipo?
  • O que é uma Função Pura?
  • O que é a Composição da Função?
  • O que é Programação Funcional?
  • O que é uma Promessa?
  • PeríciaSoft

p>p>Actualizações:
Julho de 2019 – Introdução esclarecida para explicar porque é que responder mal a esta pergunta pode custar-lhe um emprego ou muito dinheiro em salário.

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *