OOP in JavaScript
Class Fields — Public & Private (#)
Master modern class fields in JavaScript. Learn class variable declarations, initialization rules, and how to create truly private properties using the hash (#) modifier.
1. Introduction
In early class syntax, all properties had to be declared inside the constructor function using this.prop. Modern JavaScript introduces Class Fields, allowing you to declare properties directly in the class body. This includes public fields and private fields (prefixed with the hash # symbol).
2. Why It Matters
JavaScript did not historically support private variables. Developers had to use conventions like prepending underscores (_name) to signal private properties, which could still be accessed and modified. Modern private fields (#) enforce true encapsulation at the language level.
3. Real-World Analogy
Think of a Bank Account Vault:
- Public Fields (Account Holder Name): Printed clearly on your debit card. Anyone can read it (public access).
- Legacy Private Convention (_balance): Putting a sticker on a box that says "Do Not Open". It warns visitors, but anyone can still open the box and read the balance.
- Language-enforced Private Fields (#balance): A secure vault inside the bank. Only authorized managers inside the bank class can open it. If a customer tries to read or touch the vault from the lobby, they are blocked, throwing a security error immediately.
4. Public & Private Fields
Class fields are declared directly in the class body. Private fields must be declared with a hash # prefix and must be declared in the class body before they can be accessed:
5. Field Semantics
- Initialization Order: Class fields are initialized before the constructor code runs. This allows you to refer to class fields inside your constructor function.
- Instance Fields: Fields are attached directly to each object instance, not the prototype.
- Hard Privacy: Private fields cannot be deleted or modified dynamically from outside the class. Attempting to access private fields outside the class throws a compile-time SyntaxError.
6. Practical Example
This script demonstrates implementing a secure user login class using private methods and fields:
7. Common Mistakes
- Trying to declare a private property dynamically: Private properties cannot be added to an object dynamically. They must be declared in the class body before compilation. Attempting to add a new private property at runtime throws a SyntaxError.
8. Quick Quiz
Q1: What prefix is used to declare private fields and methods in modern JavaScript classes?
A) _
B) #
Answer: B — The hash (#) prefix is used to declare private fields and methods, enforcing language-level encapsulation.
9. Scenario-Based Challenge
The Encapsulated API Key Client:
An API connection class contains a sensitive property: apiKey. To prevent developers from accidentally printing the key when calling console.log(client) or serialization hooks, hide the property using a private field. Write this API client class.
10. Debugging Exercise
Explain why this class declaration throws a SyntaxError, and how to fix it:
class User {
constructor(name, secret) {
this.name = name;
// Bug: trying to assign to a private field that was not declared in the class body!
this.#secret = secret; // SyntaxError! Why?
}
}
View Solution
Diagnosis: All private properties must be declared in the class body before they can be assigned or accessed. Attempting to use #secret without declaring it first throws a SyntaxError.
Fix: Declare the private property in the class body:
class User { #secret; // Declare private property first
constructor(name, secret) { this.name = name; this.#secret = secret; // Works! } }
11. Interview Questions
🟢 Q1: Explain how private fields (#) differ from properties prefixed with an underscore (_).
Answer:
• Underscore Prefix (_prop): A developer convention signaling that a property is internal. It is still a public property, meaning it can be accessed, modified, or deleted from outside the class.
• Private Fields (#prop): Enforced at the language level. Private fields cannot be accessed or modified from outside the class. Attempting to do so throws a compile-time SyntaxError. They are also omitted from serialization hooks (like JSON.stringify()).
12. Production Considerations
- • Performance of Private Fields: In some JavaScript engines, accessing private fields can have a small performance penalty compared to standard properties. Avoid using private properties inside high-frequency execution loops.