DEV Community

Lucas Pereira de Souza
Lucas Pereira de Souza

Posted on

Closures e escopos em JavaScript

logotech

# Desvendando Closures: Como Funções Internas e Memória de Variáveis Moldam o JavaScript Moderno

## Introdução

No universo do desenvolvimento backend, especialmente com linguagens dinâmicas como JavaScript (e suas vertentes como TypeScript), a forma como gerenciamos o estado e a execução de funções é crucial para construir aplicações robustas, eficientes e de fácil manutenção. Um dos conceitos mais poderosos e, por vezes, sutilmente complexos, é o de **closures** (fechamentos). Closures nos permitem criar funções que \"lembram\" do ambiente em que foram criadas, mesmo após o término da execução da função externa. Este artigo visa desmistificar closures, explorando funções internas, a memória de variáveis e apresentando exemplos práticos em TypeScript/Node.js.

## Desenvolvimento: Funções Internas e a Persistência da Memória

### Funções Internas (Aninhadas)

Em JavaScript/TypeScript, uma função pode ser definida dentro de outra função. Essa função interna tem acesso às variáveis e parâmetros da função externa que a contém.

Enter fullscreen mode Exit fullscreen mode


typescript
function externa(): void {
let mensagem: string = \"Olá do escopo externo!\";

function interna(): void {
console.log(mensagem); // A função interna acessa 'mensagem' da função externa
}

interna();
}

externa(); // Saída: Olá do escopo externo!


### A Mágica da Memória: Closures em Ação

O verdadeiro poder surge quando a função interna é retornada pela função externa e, posteriormente, invocada. Mesmo que a função externa já tenha terminado sua execução e seus blocos de memória normalmente seriam liberados, a closure garante que as variáveis referenciadas pela função interna permaneçam acessíveis.

Imagine que a função externa cria um \"ambiente\" (o escopo léxico) e a função interna \"captura\" ou \"fecha\" sobre esse ambiente. Essa captura inclui as variáveis que estavam acessíveis no momento da criação da função interna.

Enter fullscreen mode Exit fullscreen mode


typescript
function criarContador(): () => number {
let contador: number = 0; // Variável no escopo da função externa

// A função interna (closure) é retornada
return function incrementar(): number {
contador++; // Acesso e modificação da variável 'contador'
console.log(Valor atual: ${contador});
return contador;
};
}

const meuContador = criarContador(); // A função externa 'criarContador' executa e retorna a função 'incrementar'

meuContador(); // Saída: Valor atual: 1
meuContador(); // Saída: Valor atual: 2
meuContador(); // Saída: Valor atual: 3

// 'meuContador' é uma closure. Ela \"lembra\" da variável 'contador'
// mesmo após 'criarContador' ter finalizado sua execução.


Neste exemplo, `meuContador` é uma closure. Cada vez que `meuContador()` é chamada, ela não cria uma nova variável `contador`, mas sim acessa e modifica a *mesma* variável `contador` que foi criada quando `criarContador` foi executada pela primeira vez.

## Exemplos Práticos de Closures

### 1. Fábricas de Funções (Function Factories)

Closures são ideais para criar funções com configurações específicas, sem a necessidade de usar variáveis globais.

Enter fullscreen mode Exit fullscreen mode


typescript
/**

  • Cria uma função que multiplica um número por um fator específico.
  • @param fator O número pelo qual multiplicar.
  • @returns Uma função que recebe um número e retorna o resultado da multiplicação. */ function criarMultiplicador(fator: number): (num: number) => number { // 'fator' é capturado pela closure retornada return function(num: number): number { return num * fator; }; }

const dobrar = criarMultiplicador(2);
const triplicar = criarMultiplicador(3);

console.log(Dobro de 5: ${dobrar(5)}); // Saída: Dobro de 5: 10
console.log(Triplo de 5: ${triplicar(5)}); // Saída: Triplo de 5: 15


### 2. Encapsulamento e Privacidade (Simulando Variáveis Privadas)

Embora JavaScript/TypeScript não tenha modificadores de acesso estritos como `private` em classes (até versões mais recentes com `#`), closures podem ser usadas para simular um nível de privacidade.

Enter fullscreen mode Exit fullscreen mode


typescript
function criarPessoa(nomeInicial: string) {
let _nome: string = nomeInicial; // Variável \"privada\" pelo escopo

return {
getNome: function(): string {
return _nome; // Acesso permitido apenas via getter
},
setNome: function(novoNome: string): void {
// Poderíamos adicionar validações aqui
_nome = novoNome;
}
};
}

const pessoa = criarPessoa(\"Alice\");

console.log(pessoa.getNome()); // Saída: Alice
// console.log(pessoa._nome); // Erro: Property '_nome' is private and only accessible within class '...' (ou simplesmente não acessível se não for parte do retorno)

pessoa.setNome(\"Bob\");
console.log(pessoa.getNome()); // Saída: Bob


### 3. Módulos e Padrões de Projeto

Closures são a base para a criação de módulos em JavaScript antes da introdução dos módulos ES6. Elas permitem encapsular código e expor apenas a interface necessária.

Enter fullscreen mode Exit fullscreen mode


typescript
const MeuModulo = (function() {
let contadorInterno: number = 0;

function metodoPrivado(): void {
console.log(\"Sou um método privado!\");
}

// O objeto retornado expõe apenas os métodos públicos
return {
metodoPublico: function(): void {
metodoPrivado();
contadorInterno++;
console.log(Contador atual: ${contadorInterno});
},
getContador: function(): number {
return contadorInterno;
}
};
})();

MeuModulo.metodoPublico(); // Saída: Sou um método privado! \n Contador atual: 1
MeuModulo.metodoPublico(); // Saída: Sou um método privado! \n Contador atual: 2
console.log(Valor final do contador: ${MeuModulo.getContador()}); // Saída: Valor final do contador: 2

// metodoPrivado() e contadorInterno não são acessíveis externamente.


## Conclusão

Closures são um conceito fundamental em JavaScript/TypeScript que permite que funções retenham acesso ao seu escopo léxico, mesmo após a conclusão da função externa. Essa capacidade de \"lembrar" de variáveis possibilita padrões poderosos como fábricas de funções, encapsulamento de dados e a criação de módulos. Compreender e aplicar closures efetivamente é um passo essencial para se tornar um desenvolvedor backend proficiente, capaz de escrever código mais limpo, organizado e com gerenciamento de estado mais sofisticado. Domine as closures, e você desbloqueará um novo nível de expressividade e poder em suas aplicações.
Enter fullscreen mode Exit fullscreen mode

Top comments (0)