Class Advanced Features

Med

Beyond basic class syntax, JavaScript classes support private fields (#), static members, static initialization blocks, computed property names, and patterns like mixins and method chaining. Private fields provide true encapsulation enforced by the engine.

Interactive Visualization

Tagged Templates

A tagged template literal is called
highlight`Hello ${name}!`

Key Points

  • Private fields (#) are truly private — accessing them outside the class throws a SyntaxError
  • Static methods and properties belong to the class itself, not instances
  • Static initialization blocks (static { }) run once when the class is defined
  • Public class fields are declared at the top of the class body without let/const
  • Mixins compose behavior from multiple sources since JS only supports single inheritance
  • Method chaining works by returning this from each method

Code Examples

Private Fields and Methods

class BankAccount {
  #balance = 0
  #owner

  constructor(owner, initialBalance) {
    this.#owner = owner
    this.#balance = initialBalance
  }

  #validate(amount) {
    if (amount <= 0) throw new Error('Amount must be positive')
    if (amount > this.#balance) throw new Error('Insufficient funds')
  }

  withdraw(amount) {
    this.#validate(amount)
    this.#balance -= amount
    return this.#balance
  }

  get balance() { return this.#balance }
}

const account = new BankAccount('Alice', 1000)
console.log(account.balance) // 1000
// account.#balance           // SyntaxError!

The # prefix creates truly private fields and methods enforced by the engine, not by convention.

Static Members and Init Blocks

class Config {
  static #instance = null
  static DEFAULT_TIMEOUT = 5000

  #settings

  constructor(settings) { this.#settings = settings }

  static {
    Config.#instance = new Config({
      timeout: Config.DEFAULT_TIMEOUT,
    })
  }

  static getInstance() { return Config.#instance }
  get(key) { return this.#settings[key] }
}

const config = Config.getInstance()
console.log(config.get('timeout')) // 5000

Static init blocks run when the class is first evaluated — useful for singletons and configuration.

Mixin Pattern

const Serializable = (Base) =>
  class extends Base {
    toJSON() {
      const obj = {}
      for (const key of Object.keys(this)) obj[key] = this[key]
      return JSON.stringify(obj)
    }
  }

const Validatable = (Base) =>
  class extends Base {
    validate() {
      for (const [key, value] of Object.entries(this)) {
        if (value == null) throw new Error(key + ' is required')
      }
      return true
    }
  }

class BaseUser {
  constructor(name, email) { this.name = name; this.email = email }
}

class User extends Serializable(Validatable(BaseUser)) {}

const user = new User('Alice', 'alice@example.com')
user.validate() // true
console.log(user.toJSON())

Mixins use higher-order class expressions to compose behavior since JS only supports single inheritance.

Method Chaining

class QueryBuilder {
  #table = ''
  #conditions = []
  #limit = null

  from(table) { this.#table = table; return this }
  where(cond) { this.#conditions.push(cond); return this }
  take(n) { this.#limit = n; return this }

  build() {
    let q = 'SELECT * FROM ' + this.#table
    if (this.#conditions.length) q += ' WHERE ' + this.#conditions.join(' AND ')
    if (this.#limit) q += ' LIMIT ' + this.#limit
    return q
  }
}

const query = new QueryBuilder()
  .from('users')
  .where('age > 18')
  .where('active = true')
  .take(10)
  .build()

Each method returns this, enabling fluent chaining. The builder pattern constructs complex objects step-by-step.

Common Mistakes

  • Trying to access private fields with bracket notation — obj["#field"] does not work
  • Calling static methods on instances instead of the class
  • Arrow function class fields create a new function per instance — performance concern
  • Using mixins without understanding the prototype chain order

Interview Tips

  • Contrast private fields (#) with underscore convention — # is engine-enforced
  • Static init blocks allow complex setup with access to private static fields
  • Show how mixins solve the lack of multiple inheritance
  • Method chaining key insight: returning this from each method

Related Concepts