Membros de Classe Privados e Protegidos em JavaScript
Aprenda a usar membros privados com prefixo `#` e a convenção `_` para membros protegidos em classes JavaScript, com getters e setters.
Uma classe frequentemente precisa ocultar parte de seu funcionamento interno para que o código externo não possa lê-los ou alterá-los diretamente. Esta página aborda as duas formas que o JavaScript oferece para isso: membros verdadeiramente privados declarados com o prefixo #, e a convenção de underscore _ que os desenvolvedores usam para marcar membros como "protegidos" (destinados apenas à classe e suas subclasses).
Você verá quando usar cada um, por que os campos # são genuinamente inacessíveis de fora, e como combinar campos privados com getters e setters para expor uma interface controlada e validada. Se classes são novidade para você, comece pelo capítulo Sintaxe básica de classes primeiro.
Introdução ao Encapsulamento em JavaScript
O encapsulamento é um princípio fundamental da programação orientada a objetos (POO): ele agrupa os dados (variáveis) e os métodos (funções) que operam sobre esses dados em uma única unidade — um object — e controla o acesso aos internos desse object. O objetivo é expor uma interface pública pequena e deliberada, ocultando os detalhes de implementação por trás dela.
Por que isso importa? Quando o estado interno está oculto, o código externo não pode colocar seu object em um estado inválido, e você é livre para alterar o funcionamento interno da classe sem quebrar o código que a usa. Em JavaScript, o encapsulamento é alcançado com campos e métodos privados #. JavaScript não possui um modificador protected nativo, então os desenvolvedores o simulam com uma convenção de nomenclatura (o prefixo _), conforme explicado abaixo.
Propriedades e Métodos Privados
Um membro privado de classe é declarado com o prefixo # em seu nome. Ele só pode ser acessado de dentro do corpo da classe — qualquer tentativa de lê-lo ou escrevê-lo de fora é um erro de sintaxe real, não apenas undefined. Esta é uma privacidade real, imposta pela linguagem.
Um campo deve ser declarado no corpo da classe antes de ser usado (você não pode criar um campo # dinamicamente dentro do construtor como faria com uma propriedade pública). Note também que os campos privados # são não-enumeráveis: eles não aparecem em Object.keys(), for...in, ou na saída de JSON.stringify().
Por que # é verdadeiramente privado
Ao contrário da convenção de underscore, um campo # é invisível fora da classe. Você não pode acessá-lo através de user.#name, por acesso de colchetes como user["#name"], ou por Object.keys(). A primeira forma é um erro de sintaxe; as outras simplesmente não encontram o campo.
Métodos Privados
Os métodos também podem ser privados: prefixe o nome do método com #. Um método privado é útil para auxiliares internos que os chamadores nunca devem invocar diretamente — por exemplo, lógica de validação ou formatação que suporta a API pública, mas não faz parte dela.
Propriedades e Métodos Protegidos (a convenção _)
JavaScript não possui a palavra-chave protected. Por convenção, um membro destinado a ser usado pela classe e suas subclasses — mas não pelo código externo — é prefixado com um único underscore _. Isso é puramente um sinal para outros desenvolvedores; um membro _ permanece totalmente legível e gravável de qualquer lugar. Use-o quando as subclasses precisam de acesso (um campo # não é acessível a partir de subclasses), e aceite que a proteção é por acordo, não por imposição.
Como os membros _ são herdados como qualquer propriedade normal, uma subclasse pode depender deles. Esta é a razão prática para usar a convenção em vez de # ao projetar para herança:
Encapsulamento Baseado em Acessores: Boas Práticas
Ao incorporar propriedades e métodos privados e protegidos em seus projetos JavaScript, considere as seguintes boas práticas para maximizar seus benefícios:
- Use campos privados para dados sensíveis ou invariáveis: Armazene qualquer coisa que não deva ser tocada diretamente — contadores internos, valores em cache, estado bruto — como um campo
#. Isso garante integridade e evita efeitos colaterais indesejados. - Aproveite getters e setters: Mantenha o campo privado e exponha-o por meio de um getter e setter. O setter é a sua oportunidade de validar ou transformar a entrada antes que ela alcance o campo privado, para que o object nunca possa conter um valor inválido.
No exemplo abaixo, #age só pode ser alterado por meio do setter, que rejeita números negativos:
Você também pode expor o estado como somente leitura definindo um getter sem um setter correspondente — o consumidor pode ler o valor, mas não tem como sobrescrever o campo privado subjacente.
- Aplique membros protegidos para herança: Use propriedades e métodos protegidos quando pretender que sejam acessíveis dentro das subclasses. Esta estratégia facilita uma estrutura mais flexível e hierárquica em suas aplicações.
Técnicas e Padrões Avançados
Além do básico, JavaScript permite padrões e técnicas sofisticadas para encapsular e estruturar seu código de forma mais eficaz:
- Padrão de módulo: Utilize closures e expressões de função imediatamente invocadas (IIFE) para criar escopos privados.
- Funções de fábrica: Essas funções retornam novos objects, permitindo dados privados por meio de closures, sem a necessidade da palavra-chave
new. - Proxies: Proxies em JavaScript podem ser usados para criar envoltórios protetores em torno de objects, controlando o acesso às suas propriedades e métodos.
Conclusão
Use campos e métodos # quando quiser privacidade genuína e imposta que nenhum código externo possa alcançar. Use a convenção de underscore _ quando as subclasses precisam de acesso e a proteção pode ser por acordo. Combine campos privados com getters e setters para expor uma interface controlada e validada — e getters somente leitura quando o estado deve ser observável, mas não mutável.
Tópicos relacionados
- Sintaxe básica de classes — declarando classes, construtores e métodos.
- Getters e setters de propriedades — o padrão de acessor usado ao longo desta página.
- Propriedades e métodos estáticos — membros que pertencem à própria classe, incluindo campos estáticos privados.