InterviewHubPRO
Section Overview
Q485

Question 485 of 521

Part 8: Modern JavaScript APIs, WeakRef, Proxy & Performance (464 - 521)

93%
JavaScript Internals (521 Qs)•Part 8: Modern JavaScript APIs, WeakRef, Proxy & Performance (464 - 521)

What are private class fields in JavaScript?

Private class fields (introduced in ES2022) are class properties that are only accessible within the class itself. They are prefixed with a hash symbol (#) and provide true encapsulation in JavaScript classes.

Key Features:

  1. True Privacy: Cannot be accessed from outside the class, even using bracket notation
  2. Instance Privacy: Each instance has its own private fields
  3. Subclass Isolation: Private fields are not inherited or accessible by subclasses
  4. Hard Private: Unlike convention-based privacy (e.g., _privateField), these are enforced by the language

Syntax and Examples:

javascript
 class BankAccount {
   // Private fields (must be declared at class level)
   #balance = 0;
   #accountNumber;
   #pin;

   // Public field
   accountHolder;

   constructor(holder, accountNumber, initialDeposit, pin) {
     this.accountHolder = holder;
     this.#accountNumber = accountNumber;
     this.#balance = initialDeposit;
     this.#pin = pin;
   }

   // Private method
   #validatePin(inputPin) {
     return this.#pin === inputPin;
   }

   // Public methods can access private fields
   deposit(amount) {
     if (amount > 0) {
       this.#balance += amount;
       return true;
     }
     return false;
   }

   withdraw(amount, pin) {
     if (!this.#validatePin(pin)) {
       throw new Error('Invalid PIN');
     }
     if (amount > 0 && amount <= this.#balance) {
       this.#balance -= amount;
       return amount;
     }
     throw new Error('Insufficient funds');
   }

   getBalance(pin) {
     if (!this.#validatePin(pin)) {
       throw new Error('Invalid PIN');
     }
     return this.#balance;
   }

   // Static private fields
   static #bankName = 'SecureBank';
   
   static getBankName() {
     return this.#bankName;
   }
 }

 // Usage
 const account = new BankAccount('Alice', '123456', 1000, '1234');

 account.deposit(500);
 console.log(account.getBalance('1234')); // 1500

 // Attempting to access private fields throws an error
 console.log(account.#balance); // SyntaxError: Private field '#balance' must be declared in an enclosing class
 console.log(account['#balance']); // undefined (bracket notation doesn't work)

 // Even reflection doesn't work
 console.log(Object.keys(account)); // ['accountHolder']
 console.log(Reflect.ownKeys(account)); // Does not include private fields in public APIs

Benefits over Convention-Based Privacy:

javascript
 // Old way (convention-based, not truly private)
 class OldAccount {
   constructor(balance) {
     this._balance = balance; // Convention: underscore means "private"
   }

   getBalance() {
     return this._balance;
   }
 }

 const oldAcc = new OldAccount(1000);
 console.log(oldAcc._balance); // 1000 (accessible! Not truly private)
 oldAcc._balance = 999999; // Can be modified from outside

 // New way (truly private)
 class NewAccount {
   #balance;

   constructor(balance) {
     this.#balance = balance;
   }

   getBalance() {
     return this.#balance;
   }
 }

 const newAcc = new NewAccount(1000);
 // console.log(newAcc.#balance); // SyntaxError
 // newAcc.#balance = 999999; // SyntaxError

Private Fields with Inheritance:

javascript
 class Parent {
   #privateField = 'parent private';

   getPrivate() {
     return this.#privateField;
   }
 }

 class Child extends Parent {
   #privateField = 'child private'; // Different field, doesn't override

   getChildPrivate() {
     return this.#privateField;
   }
 }

 const child = new Child();
 console.log(child.getPrivate()); // 'parent private'
 console.log(child.getChildPrivate()); // 'child private'