Online Compiler logoOnline Compiler

JavaScript Classes & Inheritance: Complete OOP Guide

What You'll Learn:

  • ✅ ES6 class syntax and how it works
  • ✅ Constructors and initialization
  • ✅ Instance methods and properties
  • ✅ Inheritance with extends and super
  • ✅ Static methods and properties
  • ✅ Getters and setters
  • ✅ Private fields with #
  • ✅ Prototypal inheritance under the hood
  • ✅ Common OOP patterns in JavaScript
  • ✅ Interview questions about classes

What are JavaScript Classes?

Classes in JavaScript are syntactic sugar over prototypal inheritance. Introduced in ES6 (2015), they provide a cleaner, more intuitive syntax for creating objects and implementing inheritance. While classes look like traditional class-based OOP, JavaScript still uses prototypes under the hood.

Classes make it easier to organize code, create reusable blueprints for objects, and establish inheritance hierarchies. They're essential for building larger applications with proper OOP structure.

Class Syntax & Basics

Basic Class Definition

// ES6 Class syntax
class Animal {
  // Constructor - runs when creating new instance
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }
  
  // Instance method
  speak() {
...

Classes act as blueprints for creating objects. Each instance has its own properties but shares methods.

Understanding the Constructor

The constructor is a special method that runs automatically when you create a new instance of the class using the `new` keyword. It's perfect for initializing instance properties and performing setup tasks.

Constructor Deep Dive

class User {
  constructor(username, email) {
    // Initialize instance properties
    this.username = username;
    this.email = email;
    this.createdAt = new Date();
    this.isActive = true;
    
    console.log(`New user ${username} created`);
  }
...

Constructors initialize instance properties when new instances are created.

Inheritance with extends & super

Inheritance allows one class to inherit properties and methods from another class. Use `extends` to create a subclass and `super` to access parent class methods and properties.

Class Inheritance

// Parent class (base class)
class Animal {
  constructor(name) {
    this.name = name;
  }
  
  speak() {
    console.log(`${this.name} makes a sound`);
  }
}
...

Inheritance creates a hierarchy of classes where child classes reuse and extend parent class functionality.

Static Methods & Properties

Static methods and properties belong to the class itself, not to instances. They're useful for utility functions or shared data that all instances should access.

Static Members

class Counter {
  static count = 0; // Static property - shared by all instances
  
  constructor(name) {
    this.name = name;
    Counter.count++; // Increment class counter
  }
  
  static getCount() {
    return `Total instances created: ${Counter.count}`;
...

Static methods and properties are shared by all instances and called on the class, not instances.

Getters & Setters

Getters and setters allow you to define custom behavior when accessing or modifying properties. They look like properties but execute functions, enabling validation and computed properties.

Getters and Setters

class Person {
  constructor(firstName, lastName, age) {
    this._firstName = firstName; // Convention: underscore for private-like
    this._lastName = lastName;
    this._age = age;
  }
  
  // Getter - accessed like property
  get fullName() {
    return `${this._firstName} ${this._lastName}`;
...

Getters and setters let you define computed or validated properties that feel like normal property access.

Private Fields with #

Private fields, introduced in ES2022, are truly private at the language level. They're prefixed with # and cannot be accessed outside the class, unlike the _convention approach.

Private Fields

class BankAccount {
  #balance = 0; // Private field - truly inaccessible outside class
  
  constructor(initialBalance) {
    this.#balance = initialBalance;
  }
  
  deposit(amount) {
    if (amount > 0) {
      this.#balance += amount;
...

Private fields with # provide true privacy enforced by JavaScript itself, not just convention.

super Keyword Deep Dive

The `super` keyword allows you to call parent class methods and access parent class properties. It's essential for effective inheritance.

Using super Keyword

class Vehicle {
  constructor(brand, year) {
    this.brand = brand;
    this.year = year;
  }
  
  getInfo() {
    return `${this.brand} (${this.year})`;
  }
  
...

super lets you call parent class methods and constructors, enabling method chaining in inheritance hierarchies.

Classes Under the Hood - Prototypes

Classes are syntactic sugar over JavaScript's prototypal inheritance. Understanding how classes compile to prototypes helps you debug and understand JavaScript better.

Classes vs Prototypes Equivalence

// CLASS WAY (modern, recommended)
class Animal {
  constructor(name) {
    this.name = name;
  }
  
  speak() {
    console.log(`${this.name} speaks`);
  }
}
...

Classes are syntactic sugar over prototypal inheritance. Both approaches work, but classes are more intuitive.

Common OOP Patterns in JavaScript

1. Singleton Pattern

Singleton Pattern

class Database {
  static instance = null;
  
  constructor() {
    if (Database.instance) {
      return Database.instance;
    }
    this.connected = false;
    Database.instance = this;
  }
...

Singleton pattern ensures only one instance of a class exists throughout the application.

2. Factory Pattern

Factory Pattern

class User {}
class Admin {}

class UserFactory {
  static createUser(role) {
    if (role === "admin") {
      return new Admin();
    } else {
      return new User();
    }
...

Factory pattern creates objects without specifying exact classes, centralizing object creation logic.

Interview Q&A

Q: What's the difference between classes and constructor functions?

A: Classes are syntactic sugar over constructor functions. Both use prototypal inheritance under the hood. Classes are the modern, cleaner approach and are hoisted differently than constructor functions.

Q: When should you use inheritance?

A: Use inheritance when you have "is-a" relationships (Dog is an Animal). For "has-a" relationships, use composition instead. Prefer composition over inheritance to avoid deep hierarchies.

Q: What happens if you forget the `new` keyword?

A: Classes require `new` and will throw an error if used without it. Constructor functions called without `new` will have `this` bound to the global object, potentially creating global variables. Always use `new`.

Summary

  • 🎯 Classes provide clean OOP syntax over prototypal inheritance
  • 🎯 Constructors initialize instances with properties
  • 🎯 Methods are functions that belong to class instances
  • 🎯 Use `extends` and `super` for inheritance
  • 🎯 Static members belong to the class, not instances
  • 🎯 Getters and setters provide computed/validated properties
  • 🎯 Private fields with # ensure true privacy
  • 🎯 Understand prototypes to debug class issues
  • 🎯 Prefer composition over complex inheritance hierarchies