Iron-Clad Encapsulation
Private fields (starting with #) are not just a naming convention — they are physically enforced by the JavaScript engine.
How # Fields Differ From _ Convention
| Feature | _field (convention) | #field (private) |
|---|---|---|
| Actually private? | No — just a warning sign | Yes — enforced by engine |
| Accessible via string? | Yes: obj['_field'] | No — obj['#field'] returns undefined |
| Visible in for..in? | Yes | No |
| Error timing | Runtime (if accessed wrong) | Compile-time (SyntaxError) |
class User {
#password = '12345';
checkPassword(input) {
return this.#password === input;
}
}
const user = new User();
console.log(user.checkPassword('12345')); // true
console.log(user.#password); // SyntaxError — blocked at parse time!
Important
Private fields are NOT inherited. Even a child class cannot read a #field from its parent. If child classes need access, use the _underscore convention or provide getter/setter methods in the parent class.
Tip
Use private fields for truly sensitive data (passwords, tokens, internal counters) or complex internal state that external code should never be able to corrupt.