Private Class Fields in JavaScript
Private class fields use `#` names and can only be accessed by code belonging to the class that declares the corresponding private name. They provide language-level encapsulation rather than relying on naming conventions such as `_value`.
A private field is declared directly in a class with a `#` prefix, such as `#count`. Its private name is distinct from a normal property named `count`, and outside code cannot access the private field with ordinary property syntax.
Private fields are checked by the JavaScript language, not merely hidden by convention. An expression such as `obj.#count` is only valid where the relevant private name is in scope, typically inside the declaring class. Attempting to access it externally is a syntax error rather than a normal `undefined` property lookup.
Private fields belong to each class instance unless declared as a private static field. They are initialized when an instance is created, either from a field initializer or through the class initialization process. A subclass does not automatically gain access to a superclass's private fields; the private name is tied to the class that declared it.
Private fields also differ from ordinary properties in reflection behavior. They are not ordinary keys returned by `Object.keys()`, and APIs such as `Object.getOwnPropertyNames()` do not expose private field names. This makes them useful when an implementation detail should remain inaccessible through normal object-property mechanisms.
Key points
- Declare private instance fields with `#name` inside a class.
- Private names are enforced by the language and cannot be accessed through ordinary external property syntax.
- A subclass cannot directly access a superclass's private field.
- Private fields are not ordinary object properties and are absent from standard property-key reflection.
- Use methods or accessors when external code needs controlled access to private state.
Interview questions
How do JavaScript private class fields work?
A private field is declared with a `#` prefix inside a class. Its private name can be accessed only by code that has access to that class's corresponding private name. External code cannot use normal property syntax to read or write it. This gives JavaScript language-enforced encapsulation instead of relying on naming conventions.
Can a subclass access a private field declared by its superclass?
No, not directly. A private field's name is associated with the class that declares it, so a subclass does not inherit access to that private name. The superclass can expose behavior through methods or accessors if subclasses or other callers need controlled access.
Are private class fields visible through `Object.keys()` or `Object.getOwnPropertyNames()`?
No. Private fields are not ordinary string- or symbol-keyed properties, so standard property enumeration APIs do not expose their names. Code that needs access must use operations permitted by the declaring class, such as its methods. This is one of the important differences between private fields and convention-based properties.
What is the difference between `#value` and `this.value` inside a class?
`#value` refers to the class's private field named `value`, while `this.value` refers to an ordinary property whose key is the string `"value"`. They are separate namespaces and can coexist on the same object. Code outside the class can access `this.value` if it is public, but it cannot directly access `#value`.
When would you choose private fields over closures or public properties?
Private fields are useful when state should remain encapsulated while still being naturally associated with class instances. They make the privacy boundary explicit in the class definition and are enforced by the language. Closures can also hide state, but they organize that state through lexical scope rather than an object's private field mechanism. Public properties are preferable when callers are intentionally expected to inspect or modify the state directly.