Da trilha de JavaScript Este conceito ainda não saiu como card do dia. ir para o card de hoje

JavaScript Funções Intermediário

Escopo e closures

Em JavaScript, escopo é a região do código onde uma variável é acessível. O escopo pode ser global, de função ou de bloco (delimitado por {}). Variáveis declaradas com var têm escopo de função (ou global), enquanto let e const têm escopo de bloco. Essa diferença é crucial para entender closures e evitar bugs.

Closure é a capacidade de uma função interna acessar variáveis da função externa mesmo depois que a função externa já retornou. Isso acontece porque a função interna mantém uma referência ao ambiente léxico onde foi criada. Closures são a base de padrões como funções fábrica e módulos.

Funções fábrica são funções que retornam outras funções (ou objetos) e usam closures para encapsular estado privado. Cada chamada da fábrica cria um novo escopo independente, então as funções retornadas não compartilham estado (a menos que desejado).

Um cuidado especial ocorre com closures em loops. Se usarmos var para a variável do loop, todas as funções criadas dentro do loop compartilham a mesma variável, resultando no valor final após o término do loop. Com let, cada iteração cria um novo escopo, e cada closure captura o valor correto daquela iteração.

Pontos-chave

  • Escopo léxico significa que o acesso a variáveis é determinado pela posição da função no código-fonte, não por onde ela é chamada.
  • Uma closure é criada quando uma função interna referencia variáveis da função externa, mantendo-as vivas mesmo após a execução da função externa.
  • Funções fábrica usam closures para criar instâncias independentes com estado privado.
  • Em loops, usar var faz todas as closures compartilharem a mesma variável; usar let cria um novo escopo por iteração.
  • Closures podem causar vazamentos de memória se não forem usadas com cuidado, pois mantêm referências a variáveis externas.
escopo_closures.js
// Exemplo de escopo e closures em JavaScript

// Escopo global
const global = 'global';

function externa() {
  const externaVar = 'externa';

  function interna() {
    // Acessa variáveis dos escopos externo e global
    console.log(global, externaVar);
  }

  return interna;
}

const closure = externa();
closure(); // global externa

// Função fábrica: cria contadores independentes
function criarContador() {
  let count = 0; // estado privado
  return function() {
    count++;
    return count;
  };
}

const c1 = criarContador();
const c2 = criarContador();
console.log(c1()); // 1
console.log(c1()); // 2
console.log(c2()); // 1 (independente)

// Closure em loop com let
const funcs = [];
for (let i = 0; i < 3; i++) {
  funcs.push(() => console.log(i));
}
funcs[0](); // 0
funcs[1](); // 1
funcs[2](); // 2

// Com var, todas imprimiriam 3 (último valor)

Exercícios

  1. 1
    Fácil

    Contador com closure

    Crie uma função criarContador que retorna uma função. Cada chamada da função retornada incrementa e retorna um contador interno. O contador deve começar em 0 e ser privado (não acessível de fora).

    Resolver
  2. 2
    Médio

    Função fábrica de multiplicadores

    Crie uma função criarMultiplicador que recebe um número fator e retorna uma função que multiplica seu argumento por fator. Em seguida, use-a para criar dobro e triplo e teste com o valor 5.

    Resolver
  3. 3
    Desafio

    Closures em loop com var vs let

    Crie um array de funções que, ao serem chamadas, imprimem o índice do loop (0, 1, 2). Primeiro, implemente usando var e explique por que não funciona corretamente. Depois, corrija usando let. Por fim, implemente uma terceira versão que funcione com var usando uma IIFE (Immediately Invoked Function Expression).

    Resolver

Continue estudando