Skip to Content
Course content

76: Practice Exercise: Building a Class Hierarchy for Shapes

Click on the "Edit" button in the top corner of the screen to edit your slide content.

Wait, why bother with a base Shape class if every shape calculates area differently?

I get this question a lot. It feels redundant to create a Shape class if you're just going to overwrite the getArea() method in Circle and Rectangle. But here's the thing: it's not about the implementation; it's about the contract.

Imagine you're building a drawing app. You have an array containing fifty different shapes—some circles, some squares, some triangles. Without a base class, you'd have to check the type of every single object before calling its area method. With a hierarchy, you can just loop through them and call shape.getArea() without caring what the shape actually is. That's polymorphism in action.

class Shape {
  constructor(color) {
    this.color = color;
  }

  getArea() {
    return 0; // Default implementation
  }
}

class Circle extends Shape {
  constructor(color, radius) {
    super(color);
    this.radius = radius;
  }

  getArea() {
    return Math.PI * this.radius ** 2;
  }
}

See how Circle inherits color but provides its own logic for getArea()? It keeps your code clean and predictable.

When exactly do I need to use super(), and what happens if I forget it?

In JavaScript, if your subclass has its own constructor, you must call super() before you try to touch this. If you don't, JavaScript will throw a ReferenceError. I've spent way too many hours debugging this in my early days.

Think of super() as the call that tells the parent class, "Hey, go ahead and do your setup first." Once the parent class has initialized its properties (like the color in our Shape example), then your subclass can add its own specific properties (like radius or width).

class Rectangle extends Shape {
  constructor(color, width, height) {
    // super(color); // If I comment this out, the next line crashes!
    this.width = width;
    this.height = height;
  }
}

Can I force my subclasses to actually implement a method?

Coming from languages like Java or C#, you might be looking for "abstract classes." JavaScript doesn't have those natively. However, we can mimic that behavior. If you want to ensure that any developer who creates a new shape (including your future self) remembers to write a getArea() method, don't just return 0 in the base class—throw an error instead.

I do this all the time in production code. It turns a silent bug (getting a 0 area) into an explicit crash that tells you exactly what you forgot to do.

class Shape {
  getArea() {
    throw new Error("getArea() must be implemented by the subclass");
  }
}

class Triangle extends Shape {
  constructor(color, base, height) {
    super(color);
    this.base = base;
    this.height = height;
  }
  
  // If I forget to define getArea() here, the app will 
  // throw the error from the Shape class the moment I call it.
}



📋 Practical Task

Exercise: The Multi-Shape Area Calculator

Your goal is to build a small shape management system. Implement the following:

  • A base class Shape that takes a name in the constructor and has a getArea() method that throws an error if not overridden.
  • A Circle subclass that takes name and radius, and correctly calculates its area.
  • A Rectangle subclass that takes name, width, and height, and correctly calculates its area.
  • A Square subclass that extends Rectangle (since a square is just a rectangle with equal sides), taking only name and sideLength.

Finally, create an array containing one instance of each shape and use a forEach loop to print a string for each: "[Name] has an area of [Area]".

Rating
0 0

There are no comments for now.

to be the first to leave a comment.