-
Section 1: Getting Started
-
Section 2: Core Syntax and Types
-
Section 3: Strings and Numbers in Depth
-
Section 4: Control Flow
-
Section 5: Functions
-
Section 6: Objects and Arrays
-
Section 7: Maps, Sets, and Symbols
-
Section 8: Asynchronous JavaScript
-
Section 9: Object-Oriented and Prototypes
-
Section 10: The DOM
-
Section 11: Browser APIs
-
Section 12: Modern JavaScript (ES2015-ES2025)
-
Section 13: Functional Programming Patterns
-
Section 14: Error Handling and Debugging
-
Section 15: Testing
-
Section 16: Accessibility for JavaScript Developers
-
Section 17: Internationalization and Localization
-
Section 18: Performance
-
Section 19: Node.js Fundamentals
-
Section 20: Regular Expressions
-
Section 21: Design Patterns in JavaScript
-
Section 22: Security Basics
-
Section 23: Data Structures and Algorithms in JavaScript
-
Section 24: Practical Projects
-
Section 25: More Advanced Async Patterns
-
Section 26: More Object and Class Practice
-
Section 27: Working with Dates and Internationalization
-
Section 28: Web Components
-
Section 29: More DOM and Browser Practice
-
Section 30: Build Tooling for Vanilla JavaScript
-
Section 31: More Practice Projects
-
Section 32: Interview and Algorithm Practice
-
Section 33: Error Objects (MDN Reference)
-
Section 34: TypedArrays and Binary Data
-
Section 35: Reflection and Metaprogramming (MDN Reference)
-
Section 36: More Global Functions (MDN Reference)
76: Practice Exercise: Building a Class Hierarchy for Shapes
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
Shapethat takes anamein the constructor and has agetArea()method that throws an error if not overridden. - A
Circlesubclass that takesnameandradius, and correctly calculates its area. - A
Rectanglesubclass that takesname,width, andheight, and correctly calculates its area. - A
Squaresubclass that extends Rectangle (since a square is just a rectangle with equal sides), taking onlynameandsideLength.
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]".
There are no comments for now.