Module: OOP and Prototypes

Classes

JavaScript Essentials: OOP and Prototypes -> Classes

This document covers JavaScript Classes, building upon the foundation of Prototypes and Object-Oriented Programming (OOP).

Introduction

Before ES6 (ECMAScript 2015), JavaScript relied heavily on prototype-based inheritance for implementing OOP concepts. While powerful, it could be verbose and less intuitive for developers coming from class-based languages. ES6 introduced the class keyword, providing a more familiar syntax for creating and working with objects and inheritance.

Important Note: JavaScript classes are syntactic sugar over the existing prototype-based inheritance. They don't introduce a new inheritance model; they simply make the existing one easier to read and write.

Defining a Class

The class keyword is used to define a class. Here's a basic example:

class Animal {
  constructor(name, species) {
    this.name = name;
    this.species = species;
  }

  makeSound() {
    console.log("Generic animal sound");
  }

  getName() {
    return this.name;
  }
}

// Creating an instance (object) of the class
const myAnimal = new Animal("Buddy", "Dog");
console.log(myAnimal.getName()); // Output: Buddy
myAnimal.makeSound(); // Output: Generic animal sound

Explanation:

  • class Animal { ... }: Defines a class named Animal.
  • constructor(name, species) { ... }: The constructor is a special method that's called when a new object is created using the new keyword. It initializes the object's properties. this refers to the newly created object.
  • this.name = name;: Assigns the value of the name parameter to the name property of the object.
  • makeSound() { ... }: A method (function) associated with the Animal class. All instances of Animal will have access to this method.
  • new Animal("Buddy", "Dog"): Creates a new instance of the Animal class, passing "Buddy" and "Dog" as arguments to the constructor.

Methods

Methods are functions defined within a class. They operate on the object's data (properties). As seen in the example above, methods are defined using the standard function syntax.

Class Inheritance (Extending Classes)

Inheritance allows you to create new classes (child classes) based on existing classes (parent classes). The child class inherits the properties and methods of the parent class and can add its own.

class Dog extends Animal {
  constructor(name, breed) {
    // Call the parent class's constructor
    super(name, "Dog"); // Always call super() first in the constructor
    this.breed = breed;
  }

  makeSound() {
    console.log("Woof!"); // Override the parent's makeSound method
  }

  fetch() {
    console.log("Fetching the ball!");
  }
}

const myDog = new Dog("Max", "Golden Retriever");
console.log(myDog.getName()); // Output: Max (inherited from Animal)
myDog.makeSound(); // Output: Woof! (overridden method)
myDog.fetch(); // Output: Fetching the ball! (Dog-specific method)
console.log(myDog.species); // Output: Dog (inherited from Animal)

Explanation:

  • class Dog extends Animal { ... }: Defines a class Dog that inherits from the Animal class.
  • super(name, "Dog");: Calls the constructor of the parent class (Animal). It's crucial to call super() before accessing this in the child class's constructor. It passes the necessary arguments to the parent's constructor to initialize the inherited properties.
  • makeSound() { ... }: Overrides the makeSound() method from the Animal class. The Dog class provides its own implementation of this method.
  • fetch() { ... }: A method specific to the Dog class.

Static Methods and Properties

Static methods and properties belong to the class itself, not to instances of the class. They are accessed using the class name, not an object instance.

class MathHelper {
  static add(x, y) {
    return x + y;
  }

  static PI = 3.14159;
}

console.log(MathHelper.add(5, 3)); // Output: 8
console.log(MathHelper.PI); // Output: 3.14159

// You cannot access static members through an instance:
const helper = new MathHelper();
// console.log(helper.add(5,3)); // This will throw an error

Explanation:

  • static add(x, y) { ... }: Defines a static method named add.
  • static PI = 3.14159;: Defines a static property named PI.
  • MathHelper.add(5, 3): Calls the static method add using the class name MathHelper.

Getters and Setters

Getters and setters allow you to control access to an object's properties. They provide a way to intercept property access and modification.

class Circle {
  constructor(radius) {
    this._radius = radius; // Use an underscore to indicate a "private" property
  }

  get radius() {
    return this._radius;
  }

  set radius(newRadius) {
    if (newRadius > 0) {
      this._radius = newRadius;
    } else {
      console.error("Radius must be positive.");
    }
  }

  get area() {
    return Math.PI * this._radius * this._radius;
  }
}

const myCircle = new Circle(5);
console.log(myCircle.radius); // Output: 5 (uses the getter)
myCircle.radius = 10; // Uses the setter
console.log(myCircle.radius); // Output: 10
console.log(myCircle.area); // Output: 314.159... (uses the getter)
myCircle.radius = -2; // Output: Radius must be positive.

Explanation:

  • get radius() { ... }: Defines a getter for the radius property. It returns the value of the internal property _radius.
  • set radius(newRadius) { ... }: Defines a setter for the radius property. It allows you to set the value of _radius, but it includes validation to ensure the radius is positive.
  • _radius: Using an underscore (_) before a property name is a common convention in JavaScript to indicate that the property is intended to be "private" (though it's not truly private). It signals to other developers that they shouldn't directly access or modify this property.
  • area: A getter for a calculated property.

Key Takeaways

  • JavaScript classes provide a more structured and readable syntax for OOP.
  • They are built on top of the existing prototype-based inheritance model.
  • constructor initializes object properties.
  • extends enables inheritance.
  • super() calls the parent class's constructor.
  • static defines class-level methods and properties.
  • Getters and setters control property access and modification.

Resources