Miembros de Clase Privados y Protegidos en JavaScript
Aprende a usar campos privados con # y la convención _ en JavaScript para encapsular datos, validar entradas y diseñar APIs de clase seguras.
Una clase a menudo necesita ocultar parte de su funcionamiento interno para que el código externo no pueda leerlo ni modificarlo directamente. Esta página cubre las dos formas en que JavaScript permite hacer esto: miembros verdaderamente privados declarados con el prefijo #, y la convención de guion bajo _ que los desarrolladores usan para marcar miembros como "protegidos" (destinados solo a la clase y sus subclases).
Verás cuándo usar cada uno, por qué los campos # son genuinamente inaccesibles desde fuera, y cómo combinar campos privados con getters y setters para exponer una interfaz controlada y validada. Si las clases son nuevas para ti, comienza primero con el capítulo Sintaxis básica de clases.
Introducción a la Encapsulación en JavaScript
La encapsulación es un principio fundamental de la programación orientada a objetos (POO): agrupa los datos (variables) y los métodos (funciones) que operan sobre esos datos en una sola unidad — un objeto — y controla el acceso a sus componentes internos. El objetivo es exponer una interfaz pública pequeña y deliberada mientras se ocultan los detalles de implementación detrás de ella.
¿Por qué importa esto? Cuando el estado interno está oculto, el código externo no puede poner el objeto en un estado inválido, y tienes libertad para cambiar cómo funciona la clase internamente sin romper el código que la utiliza. En JavaScript, la encapsulación se logra con campos y métodos privados #. JavaScript no tiene un modificador protected nativo, por lo que los desarrolladores lo simulan con una convención de nombres (el prefijo _), como se explica a continuación.
Propiedades y Métodos Privados
Un miembro de clase privado se declara con el prefijo # en su nombre. Solo se puede acceder a él desde dentro del cuerpo de la clase — cualquier intento de leerlo o escribirlo desde fuera es un error de sintaxis real, no simplemente undefined. Esta es una privacidad real, aplicada por el lenguaje.
Un campo debe declararse en el cuerpo de la clase antes de poder usarse (no se puede crear un campo # sobre la marcha dentro del constructor como se puede hacer con una propiedad pública). Ten en cuenta también que los campos privados # no son enumerables: no aparecen en Object.keys(), for...in, ni en la salida de JSON.stringify().
Por qué # es verdaderamente privado
A diferencia de la convención de guion bajo, un campo # es invisible fuera de la clase. No puedes acceder a él mediante user.#name, mediante acceso por corchetes como user[\"#name\"], ni a través de Object.keys(). La primera forma es un error de sintaxis; las demás simplemente no encuentran el campo.
Métodos Privados
Los métodos también pueden ser privados: se antepone el prefijo # al nombre del método. Un método privado es útil para funciones auxiliares internas que los llamadores nunca deben invocar directamente — por ejemplo, lógica de validación o formato que soporta la API pública pero no forma parte de ella.
Propiedades y Métodos Protegidos (la convención _)
JavaScript no tiene la palabra clave protected. Por convención, un miembro destinado a ser usado por la clase y sus subclases — pero no por código externo — lleva el prefijo de un guion bajo _. Esto es puramente una señal para otros desarrolladores; un miembro con _ sigue siendo completamente legible y modificable desde cualquier lugar. Úsalo cuando las subclases necesiten acceso (un campo # no es accesible desde subclases), y acepta que la protección es por acuerdo, no por aplicación forzada.
Dado que los miembros con _ se heredan como cualquier propiedad normal, una subclase puede depender de ellos. Esta es la razón práctica para usar la convención en lugar de # cuando se diseña para herencia:
Encapsulación Basada en Accesores: Mejores Prácticas
Al incorporar propiedades y métodos privados y protegidos en tus proyectos JavaScript, considera las siguientes mejores prácticas para maximizar sus beneficios:
- Usa campos privados para datos sensibles o invariantes: Almacena todo lo que no deba tocarse directamente — contadores internos, valores en caché, estado sin procesar — como un campo
#. Esto garantiza la integridad y previene efectos secundarios no deseados. - Aprovecha los getters y setters: Mantén el campo privado y exponlo a través de un getter y setter. El setter es tu oportunidad de validar o transformar la entrada antes de que llegue al campo privado, para que el objeto nunca pueda tener un valor inválido.
En el ejemplo siguiente, #age solo puede cambiarse a través del setter, que rechaza números negativos:
También puedes exponer un estado de solo lectura definiendo un getter sin un setter correspondiente — el consumidor puede leer el valor pero no tiene forma de sobrescribir el campo privado subyacente.
- Aplica miembros protegidos para la herencia: Usa propiedades y métodos protegidos cuando tengas la intención de que sean accesibles dentro de las subclases. Esta estrategia facilita una estructura más flexible y jerárquica en tus aplicaciones.
Técnicas y Patrones Avanzados
Más allá de los conceptos básicos, JavaScript permite patrones y técnicas sofisticados para encapsular y estructurar tu código de manera efectiva:
- Patrón módulo: Utiliza closures y expresiones de función invocadas inmediatamente (IIFE) para crear ámbitos privados.
- Funciones de fábrica: Estas funciones devuelven nuevos objetos, permitiendo datos privados mediante closures, sin necesidad de la palabra clave
new. - Proxies: Los Proxies de JavaScript pueden usarse para crear envoltorios protectores alrededor de objetos, controlando el acceso a sus propiedades y métodos.
Conclusión
Usa campos y métodos # cuando quieras privacidad genuina y aplicada a la que ningún código externo pueda acceder. Usa la convención de guion bajo _ cuando las subclases necesiten acceso y la protección pueda ser por acuerdo. Combina campos privados con getters y setters para exponer una interfaz controlada y validada — y getters de solo lectura cuando el estado deba ser observable pero no modificable.
Temas relacionados
- Sintaxis básica de clases — declaración de clases, constructores y métodos.
- Getters y setters de propiedades — el patrón de accesor usado a lo largo de esta página.
- Propiedades y métodos estáticos — miembros que pertenecen a la propia clase, incluidos los campos estáticos privados.