|

JavaScript 33 – Class Inheritance

Class inheritance allows you to create a new class that inherits properties and methods from an existing class. The new class (subclass/child) can reuse, extend, or override the behavior of the parent class (superclass/base).


A Quick Look at the Example

// Parent class
class Animal {
    constructor(name) {
        this.name = name;
    }

    speak() {
        return `${this.name} makes a sound.`;
    }
}

// Child class โ€” inherits from Animal
class Dog extends Animal {
    constructor(name, breed) {
        super(name); // Call parent constructor
        this.breed = breed;
    }

    bark() {
        return `${this.name} barks!`;
    }

    // Override parent method
    speak() {
        return `${this.name} barks.`;
    }
}

const dog = new Dog('Rex', 'Labrador');
console.log(dog.name);   // "Rex" (inherited)
console.log(dog.breed);  // "Labrador" (own)
console.log(dog.speak()); // "Rex barks." (overridden)
console.log(dog.bark());  // "Rex barks!" (own)

a. What is Class Inheritance?

Inheritance is a mechanism where one class (the subclass or child class) acquires the properties and methods of another class (the superclass or parent class).

Key Benefits

BenefitDescription
Code ReuseShare common logic across related classes
HierarchyModel real-world “is-a” relationships
ExtensibilityAdd or modify behavior in subclasses
PolymorphismSame method name, different behavior

The extends Keyword

Use extends to create a subclass:

class Child extends Parent {
    // ...
}

Visual:

        โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
        โ”‚   Animal    โ”‚ โ† Parent (superclass)
        โ”‚  (base)     โ”‚
        โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”˜
               โ”‚ extends
       โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
       โ”‚       โ”‚       โ”‚
       โ–ผ       โ–ผ       โ–ผ
   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”
   โ”‚ Dog  โ”‚ โ”‚ Cat  โ”‚ โ”‚ Bird โ”‚ โ† Children (subclasses)
   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

b. The super Keyword

The super keyword is used to access the parent class. It has two forms:

UsageDescription
super(args)Calls the parent constructor
super.method()Calls a parent method

Rule: super() Must Be Called First

In a subclass constructor, you must call super() before using this.

class Dog extends Animal {
    constructor(name, breed) {
        super(name);      // โœ… Must be called first
        this.breed = breed;
    }
}

// โŒ This will throw an error:
class BadDog extends Animal {
    constructor(name, breed) {
        this.breed = breed; // โŒ ReferenceError
        super(name);         // Too late!
    }
}

Why? The parent constructor is responsible for initializing this. Until super() runs, this doesn’t exist.


c. Inheritance Examples

Example 1: Basic Inheritance

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

    speak() {
        return `${this.name} makes a sound.`;
    }
}

class Dog extends Animal {
    // No constructor โ€” uses parent's
}

const dog = new Dog('Rex');
console.log(dog.name);   // "Rex"
console.log(dog.speak()); // "Rex makes a sound."

Note: If the subclass has no constructor, the parent’s constructor is used automatically.


Example 2: Adding New Properties and Methods

class Dog extends Animal {
    constructor(name, breed) {
        super(name);          // Call parent constructor
        this.breed = breed;   // New property
    }

    bark() {
        return `${this.name} barks!`; // New method
    }
}

const dog = new Dog('Rex', 'Labrador');
console.log(dog.name);   // "Rex"
console.log(dog.breed);  // "Labrador"
console.log(dog.speak()); // "Rex makes a sound." (inherited)
console.log(dog.bark());  // "Rex barks!" (own)

Example 3: Overriding Methods

A subclass can override a parent method by redefining it.

class Dog extends Animal {
    constructor(name, breed) {
        super(name);
        this.breed = breed;
    }

    // Override parent's speak()
    speak() {
        return `${this.name} barks.`;
    }
}

const dog = new Dog('Rex', 'Labrador');
console.log(dog.speak()); // "Rex barks." (overridden)

Example 4: Calling Parent Method with super.method()

You can call the parent method from within an overridden method using super.method().

class Dog extends Animal {
    constructor(name) {
        super(name);
    }

    speak() {
        const parentSpeak = super.speak(); // Call parent's speak()
        return `${parentSpeak} Actually, ${this.name} barks.`;
    }
}

const dog = new Dog('Rex');
console.log(dog.speak());
// "Rex makes a sound. Actually, Rex barks."

When to use super.method():

  • Extend parent behavior (rather than replacing it)
  • Reuse parent logic + add new behavior
  • Maintain both parent and child behavior

Example 5: Multi-Level Inheritance

Inheritance can chain across multiple levels.

class Animal {
    constructor(name) {
        this.name = name;
    }
    move() {
        return `${this.name} moves.`;
    }
}

class Mammal extends Animal {
    constructor(name, furColor) {
        super(name);
        this.furColor = furColor;
    }
    feedMilk() {
        return `${this.name} feeds milk.`;
    }
}

class Dog extends Mammal {
    constructor(name, furColor, breed) {
        super(name, furColor);
        this.breed = breed;
    }
    bark() {
        return `${this.name} barks!`;
    }
}

const dog = new Dog('Rex', 'brown', 'Labrador');
console.log(dog.move());     // "Rex moves." (from Animal)
console.log(dog.feedMilk()); // "Rex feeds milk." (from Mammal)
console.log(dog.bark());     // "Rex barks!" (own)

Chain:

Animal โ†’ Mammal โ†’ Dog

Example 6: instanceof Checks

The instanceof operator checks if an object is an instance of a class (including inherited classes).

const dog = new Dog('Rex');

console.log(dog instanceof Dog);     // true
console.log(dog instanceof Mammal);  // true
console.log(dog instanceof Animal);  // true
console.log(dog instanceof Object);  // true (everything inherits from Object)

Complete Example

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Class Inheritance</title>
    <style>
        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            max-width: 800px;
            margin: 0 auto;
            padding: 20px;
            background: #f8f9fa;
            color: #333;
            line-height: 1.6;
        }
        h1 { color: #007bff; border-bottom: 3px solid #007bff; padding-bottom: 10px; }
        h2 { color: #28a745; border-left: 4px solid #28a745; padding-left: 15px; margin-top: 30px; }
        .demo-box {
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
            margin: 15px 0;
        }
        pre {
            background: #1e1e1e;
            color: #d4d4d4;
            padding: 15px;
            border-radius: 8px;
            overflow-x: auto;
            font-family: 'Courier New', monospace;
            font-size: 0.9rem;
            line-height: 1.8;
        }
        .keyword { color: #569cd6; }
        .string { color: #ce9178; }
        .number { color: #b5cea8; }
        .function { color: #dcdcaa; }
        .comment { color: #6a9955; }
        .boolean { color: #569cd6; }
        .class-name { color: #4ec9b0; }
        #output {
            background: #e9ecef;
            padding: 15px;
            border-radius: 8px;
            margin-top: 15px;
            min-height: 40px;
            font-family: 'Courier New', monospace;
            font-size: 0.85rem;
            border-left: 4px solid #007bff;
            white-space: pre-wrap;
        }
        table {
            width: 100%;
            border-collapse: collapse;
            margin: 15px 0;
        }
        th, td {
            padding: 10px;
            border: 1px solid #ddd;
            text-align: left;
        }
        th { background: #007bff; color: white; }
        tr:nth-child(even) { background: #f8f9fa; }
        .btn {
            padding: 10px 20px;
            background: #007bff;
            color: white;
            border: none;
            border-radius: 6px;
            font-size: 1em;
            font-weight: bold;
            cursor: pointer;
            margin: 5px;
            transition: all 0.3s;
        }
        .btn:hover {
            background: #0056b3;
            transform: translateY(-2px);
        }
        .btn-success { background: #28a745; }
        .btn-success:hover { background: #1e7e34; }
        .hierarchy {
            font-family: 'Courier New', monospace;
            font-size: 0.85rem;
            background: #1e1e1e;
            color: #d4d4d4;
            padding: 20px;
            border-radius: 8px;
            margin: 15px 0;
            white-space: pre;
            overflow-x: auto;
            line-height: 1.8;
        }
        .class-display {
            font-family: 'Courier New', monospace;
            font-size: 1.05em;
            background: #f8f9fa;
            padding: 15px;
            border-radius: 8px;
            margin: 10px 0;
            border-left: 4px solid #007bff;
            white-space: pre-wrap;
            line-height: 1.8;
        }
    </style>
</head>
<body>

    <h1>Class Inheritance</h1>

    <div class="demo-box">
        <h2>1. Basic Inheritance with extends</h2>
        <pre>
<span class="keyword">class</span> <span class="class-name">Animal</span> {
    <span class="function">constructor</span>(name) {
        <span class="keyword">this</span>.name = name;
    }
    <span class="function">speak</span>() {
        <span class="keyword">return</span> <span class="string">`${this.name} makes a sound.`</span>;
    }
}

<span class="keyword">class</span> <span class="class-name">Dog</span> <span class="keyword">extends</span> <span class="class-name">Animal</span> {
    <span class="function">constructor</span>(name, breed) {
        <span class="keyword">super</span>(name); <span class="comment">// Call parent constructor</span>
        <span class="keyword">this</span>.breed = breed;
    }
    <span class="function">bark</span>() {
        <span class="keyword">return</span> <span class="string">`${this.name} barks!`</span>;
    }
    <span class="comment">// Override parent method</span>
    <span class="function">speak</span>() {
        <span class="keyword">return</span> <span class="string">`${this.name} barks.`</span>;
    }
}
        </pre>
    </div>

    <div class="demo-box">
        <h2>2. Class Hierarchy</h2>
        <div class="hierarchy">
<span style="color: #4ec9b0;">Animal</span> (base class)
  โ”œโ”€โ”€ constructor(name)
  โ””โ”€โ”€ speak()
  โ”‚
  โ””โ”€โ”€ <span style="color: #4ec9b0;">Mammal</span> (extends Animal)
        โ”œโ”€โ”€ constructor(name, furColor)
        โ”‚     โ””โ”€โ”€ super(name)
        โ”œโ”€โ”€ furColor (property)
        โ””โ”€โ”€ feedMilk()
        โ”‚
        โ””โ”€โ”€ <span style="color: #4ec9b0;">Dog</span> (extends Mammal)
              โ”œโ”€โ”€ constructor(name, furColor, breed)
              โ”‚     โ””โ”€โ”€ super(name, furColor)
              โ”œโ”€โ”€ breed (property)
              โ”œโ”€โ”€ bark()
              โ””โ”€โ”€ speak() โ† overridden
        </div>
    </div>

    <div class="demo-box">
        <h2>3. The super Keyword</h2>
        <table>
            <tr>
                <th>Usage</th>
                <th>Description</th>
                <th>Example</th>
            </tr>
            <tr>
                <td><code>super(args)</code></td>
                <td>Calls parent constructor</td>
                <td><code>super(name)</code></td>
            </tr>
            <tr>
                <td><code>super.method()</code></td>
                <td>Calls parent method</td>
                <td><code>super.speak()</code></td>
            </tr>
            <tr>
                <td><code>super.property</code></td>
                <td>Accesses parent property</td>
                <td><code>super.name</code> (rare)</td>
            </tr>
        </table>
        <p><strong>Rule:</strong> In a subclass constructor, <code>super()</code> must be called <strong>before</strong> accessing <code>this</code>.</p>
    </div>

    <div class="demo-box">
        <h2>4. Method Overriding and Extending</h2>
        <pre>
<span class="comment">// Override โ€” replace parent method</span>
<span class="keyword">class</span> <span class="class-name">Dog</span> <span class="keyword">extends</span> <span class="class-name">Animal</span> {
    <span class="function">speak</span>() {
        <span class="keyword">return</span> <span class="string">`${this.name} barks.`</span>; <span class="comment">// Completely replaces parent</span>
    }
}

<span class="comment">// Extend โ€” call parent + add behavior</span>
<span class="keyword">class</span> <span class="class-name">Dog2</span> <span class="keyword">extends</span> <span class="class-name">Animal</span> {
    <span class="function">speak</span>() {
        <span class="keyword">const</span> parentSpeak = <span class="keyword">super</span>.<span class="function">speak</span>();
        <span class="keyword">return</span> <span class="string">`${parentSpeak} Actually, ${this.name} barks.`</span>;
    }
}
        </pre>
    </div>

    <div class="demo-box">
        <h2>5. Interactive: Shape Inheritance</h2>
        <div style="margin: 10px 0;">
            <button class="btn" onclick="showShapes()">Show All Shapes</button>
            <button class="btn btn-success" onclick="addCircle()">Add Circle</button>
            <button class="btn btn-success" onclick="addRectangle()">Add Rectangle</button>
            <button class="btn" onclick="checkInstances()">Check instanceof</button>
        </div>
        <div class="class-display" id="shapeDisplay">Click a button to explore inheritance</div>
    </div>

    <div class="demo-box">
        <h2>6. Live Output โ€” All Examples</h2>
        <div id="output">Loading...</div>
    </div>

    <script>
        // ============================================
        // Class Inheritance โ€” Live Demo
        // ============================================

        let results = [];

        // 1. Basic inheritance
        results.push('๐Ÿ“Œ Basic Inheritance:\n');

        class Animal {
            constructor(name) {
                this.name = name;
            }
            speak() {
                return `${this.name} makes a sound.`;
            }
        }

        class Dog extends Animal {
            constructor(name, breed) {
                super(name);
                this.breed = breed;
            }
            bark() {
                return `${this.name} barks!`;
            }
            speak() {
                return `${this.name} barks.`;
            }
        }

        const dog = new Dog('Rex', 'Labrador');
        results.push('  const dog = new Dog("Rex", "Labrador")');
        results.push('  dog.name โ†’ "' + dog.name + '" (inherited)');
        results.push('  dog.breed โ†’ "' + dog.breed + '" (own)');
        results.push('  dog.speak() โ†’ "' + dog.speak() + '" (overridden)');
        results.push('  dog.bark() โ†’ "' + dog.bark() + '" (own)');
        results.push('');

        // 2. instanceof checks
        results.push('๐Ÿ“Œ instanceof Checks:\n');
        results.push('  dog instanceof Dog โ†’ ' + (dog instanceof Dog));
        results.push('  dog instanceof Animal โ†’ ' + (dog instanceof Animal));
        results.push('  dog instanceof Object โ†’ ' + (dog instanceof Object));
        results.push('');

        // 3. super.method() โ€” extending parent
        results.push('๐Ÿ“Œ super.method() โ€” Extending Parent:\n');

        class Cat extends Animal {
            constructor(name) {
                super(name);
            }
            speak() {
                const parentSpeak = super.speak();
                return `${parentSpeak} Also, ${this.name} meows.`;
            }
        }

        const cat = new Cat('Whiskers');
        results.push('  const cat = new Cat("Whiskers")');
        results.push('  cat.speak() โ†’ "' + cat.speak() + '"');
        results.push('  โ†’ Calls parent speak() then adds behavior');
        results.push('');

        // 4. Multi-level inheritance
        results.push('๐Ÿ“Œ Multi-Level Inheritance:\n');

        class Mammal extends Animal {
            constructor(name, furColor) {
                super(name);
                this.furColor = furColor;
            }
            feedMilk() {
                return `${this.name} feeds milk.`;
            }
        }

        class Puppy extends Mammal {
            constructor(name, furColor, breed) {
                super(name, furColor);
                this.breed = breed;
            }
            whimper() {
                return `${this.name} whimpers.`;
            }
        }

        const puppy = new Puppy('Buddy', 'golden', 'Golden Retriever');
        results.push('  const puppy = new Puppy("Buddy", "golden", "Golden Retriever")');
        results.push('  puppy.name โ†’ "' + puppy.name + '" (from Animal)');
        results.push('  puppy.furColor โ†’ "' + puppy.furColor + '" (from Mammal)');
        results.push('  puppy.breed โ†’ "' + puppy.breed + '" (own)');
        results.push('  puppy.speak() โ†’ "' + puppy.speak() + '" (from Animal)');
        results.push('  puppy.feedMilk() โ†’ "' + puppy.feedMilk() + '" (from Mammal)');
        results.push('  puppy.whimper() โ†’ "' + puppy.whimper() + '" (own)');
        results.push('');

        results.push('  Chain: ' + [
            puppy instanceof Puppy ? 'Puppy' : null,
            puppy instanceof Mammal ? 'Mammal' : null,
            puppy instanceof Animal ? 'Animal' : null,
            puppy instanceof Object ? 'Object' : null
        ].filter(Boolean).join(' โ†’ '));
        results.push('');

        // 5. Constructor chaining
        results.push('๐Ÿ“Œ Constructor Chaining:\n');
        results.push('  new Puppy("Buddy", "golden", "Golden Retriever")');
        results.push('    โ†’ Puppy constructor runs');
        results.push('    โ†’ super("Buddy", "golden") calls Mammal constructor');
        results.push('    โ†’ super("Buddy") calls Animal constructor');
        results.push('    โ†’ this.name = "Buddy"');
        results.push('    โ†’ returns to Mammal: this.furColor = "golden"');
        results.push('    โ†’ returns to Puppy: this.breed = "Golden Retriever"');
        results.push('');

        // 6. Overriding vs extending
        results.push('๐Ÿ“Œ Override vs Extend:\n');
        results.push('  OVERRIDE (replace completely):');
        results.push('    speak() { return "New behavior"; }');
        results.push('');
        results.push('  EXTEND (call parent + add):');
        results.push('    speak() {');
        results.push('      return super.speak() + " Extra!";');
        results.push('    }');
        results.push('');

        // 7. Inheritance with methods
        results.push('๐Ÿ“Œ Practical: Shape Hierarchy:\n');

        class Shape {
            constructor(name) {
                this.name = name;
            }
            area() {
                return 0;
            }
            describe() {
                return `${this.name}: area = ${this.area().toFixed(2)}`;
            }
        }

        class Circle extends Shape {
            constructor(radius) {
                super('Circle');
                this.radius = radius;
            }
            area() {
                return Math.PI * this.radius ** 2;
            }
        }

        class Rectangle extends Shape {
            constructor(width, height) {
                super('Rectangle');
                this.width = width;
                this.height = height;
            }
            area() {
                return this.width * this.height;
            }
        }

        class Square extends Rectangle {
            constructor(side) {
                super(side, side);
                this.name = 'Square';
            }
        }

        const shapes = [
            new Circle(5),
            new Rectangle(4, 6),
            new Square(3)
        ];

        shapes.forEach(shape => {
            results.push('  ' + shape.describe());
        });
        results.push('');

        // 8. Polymorphism
        results.push('๐Ÿ“Œ Polymorphism (Same Method, Different Behavior):\n');
        results.push('  All shapes have area() but compute differently:');
        shapes.forEach(s => {
            results.push('    ' + s.name + '.area() โ†’ ' + s.area().toFixed(2));
        });
        results.push('');

        // 9. Employee hierarchy
        results.push('๐Ÿ“Œ Practical: Employee Hierarchy:\n');

        class Employee {
            constructor(name, salary) {
                this.name = name;
                this.salary = salary;
            }
            getRole() {
                return 'Employee';
            }
            describe() {
                return `${this.name} โ€” ${this.getRole()} ($${this.salary})`;
            }
        }

        class Manager extends Employee {
            constructor(name, salary, department) {
                super(name, salary);
                this.department = department;
            }
            getRole() {
                return 'Manager';
            }
            describe() {
                return super.describe() + ` โ€” ${this.department} dept.`;
            }
        }

        class Developer extends Employee {
            constructor(name, salary, language) {
                super(name, salary);
                this.language = language;
            }
            getRole() {
                return `Developer (${this.language})`;
            }
        }

        const employees = [
            new Employee('Alice', 50000),
            new Manager('Bob', 90000, 'Engineering'),
            new Developer('Carol', 75000, 'JavaScript')
        ];

        employees.forEach(emp => {
            results.push('  ' + emp.describe());
        });
        results.push('');

        // 10. Error handling with inheritance
        results.push('๐Ÿ“Œ Practical: Custom Errors:\n');

        class AppError extends Error {
            constructor(message, code) {
                super(message);
                this.name = 'AppError';
                this.code = code;
            }
        }

        class ValidationError extends AppError {
            constructor(message, field) {
                super(message, 'VALIDATION_ERROR');
                this.name = 'ValidationError';
                this.field = field;
            }
        }

        class NotFoundError extends AppError {
            constructor(resource) {
                super(`${resource} not found`, 'NOT_FOUND');
                this.name = 'NotFoundError';
            }
        }

        const errors = [
            new ValidationError('Invalid email', 'email'),
            new NotFoundError('User')
        ];

        errors.forEach(err => {
            results.push('  ' + err.name + ': ' + err.message + ' (code: ' + err.code + ')');
        });

        results.push('');
        results.push('  Error hierarchy:');
        results.push('    ValidationError instanceof Error โ†’ ' + (errors[0] instanceof Error));
        results.push('    ValidationError instanceof AppError โ†’ ' + (errors[0] instanceof AppError));

        document.getElementById('output').textContent = results.join('\n');

        // ============================================
        // Interactive: Shape Inheritance
        // ============================================

        // Reuse Shape, Circle, Rectangle, Square classes from above
        const interactiveShapes = [];

        function showShapes() {
            const display = document.getElementById('shapeDisplay');

            if (interactiveShapes.length === 0) {
                display.textContent = 'No shapes yet. Click "Add Circle" or "Add Rectangle".';
                return;
            }

            let text = 'All Shapes:\n';
            text += 'โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n';
            interactiveShapes.forEach((s, i) => {
                text += `${i + 1}. ${s.describe()}\n`;
            });
            display.textContent = text;
        }

        function addCircle() {
            const r = Math.floor(Math.random() * 8) + 2;
            const circle = new Circle(r);
            interactiveShapes.push(circle);
            updateShapeDisplay('Added ' + circle.describe());
        }

        function addRectangle() {
            const w = Math.floor(Math.random() * 8) + 2;
            const h = Math.floor(Math.random() * 8) + 2;
            const rect = new Rectangle(w, h);
            interactiveShapes.push(rect);
            updateShapeDisplay('Added ' + rect.describe());
        }

        function updateShapeDisplay(message) {
            const display = document.getElementById('shapeDisplay');
            let text = message + '\n';
            text += 'โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n';
            text += `Total shapes: ${interactiveShapes.length}\n\n`;
            interactiveShapes.forEach((s, i) => {
                text += `${i + 1}. ${s.describe()}\n`;
            });
            display.textContent = text;
        }

        function checkInstances() {
            const display = document.getElementById('shapeDisplay');

            if (interactiveShapes.length === 0) {
                display.textContent = 'Add some shapes first!';
                return;
            }

            const shape = interactiveShapes[interactiveShapes.length - 1];
            display.textContent =
                `Instanceof checks for "${shape.name}":\n` +
                `โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n` +
                `shape instanceof Circle    โ†’ ${shape instanceof Circle}\n` +
                `shape instanceof Rectangle โ†’ ${shape instanceof Rectangle}\n` +
                `shape instanceof Square    โ†’ ${shape instanceof Square}\n` +
                `shape instanceof Shape     โ†’ ${shape instanceof Shape}\n` +
                `shape instanceof Object    โ†’ ${shape instanceof Object}\n` +
                `\n` +
                `shape.constructor.name     โ†’ ${shape.constructor.name}`;
        }
    </script>

</body>
</html>

Quick Reference

Inheritance Syntax

FeatureSyntaxExample
Extend classclass B extends A { }class Dog extends Animal { }
Call parent constructorsuper(args)super(name)
Call parent methodsuper.method()super.speak()
Check instanceobj instanceof Classdog instanceof Animal

Rules of super()

RuleDescription
Must call firstBefore using this in subclass constructor
Only in subclassCannot use super() in a class without extends
Only in constructorsuper() for constructor; super.method() in any method
Only onceCan only call super() once per constructor

Override vs Extend

ApproachBehaviorExample
OverrideReplace parent methodspeak() { return "New"; }
ExtendCall parent + addspeak() { return super.speak() + " more"; }

instanceof Behavior

const dog = new Dog('Rex');

dog instanceof Dog     // true (own class)
dog instanceof Animal  // true (parent class)
dog instanceof Object  // true (everything inherits from Object)

Best Practices

โœ… Do This:

// Call super() first in subclass constructor
class Dog extends Animal {
    constructor(name, breed) {
        super(name);       // โœ… First
        this.breed = breed;
    }
}

// Use super.method() to extend parent behavior
class Dog extends Animal {
    speak() {
        return super.speak() + ' Woof!'; // โœ… Reuse + extend
    }
}

// Check instanceof for type safety
if (animal instanceof Dog) { }

// Use inheritance for "is-a" relationships
class Dog extends Animal { }  // Dog IS-A Animal

// Prefer composition over deep inheritance
class Logger { }              // โœ… Composition
class UserService {
    constructor(logger) { }
}

โŒ Don’t Do This:

// Don't access this before super()
class Dog extends Animal {
    constructor(name) {
        this.name = name; // โŒ ReferenceError
        super();
    }
}

// Don't forget super() in subclass with constructor
class Dog extends Animal {
    constructor(name) {
        // Missing super()! โŒ Error
        this.name = name;
    }
}

// Don't over-deep inheritance chains
class A extends B extends C extends D { } // โŒ Hard to maintain

// Don't use inheritance for "has-a" relationships
class Car extends Engine { } // โŒ A car HAS an engine

// Don't shadow private fields
class Dog extends Animal {
    #name; // โŒ Different from parent's #name
}

Common Pitfalls

PitfallProblemSolution
Missing super()ReferenceErrorAlways call super() first
this before super()ReferenceErrorCall super() before this
Deep inheritanceHard to maintainPrefer composition
Overriding constructorsForgetting to call parentUse super()
Shadowing methodsWrong behaviorUse super.method()
Forgetting extendssuper() failsAdd extends

When to Use Inheritance

ScenarioUse Inheritance?
“Is-a” relationshipโœ… Yes
Shared behaviorโœ… Yes
Specialized variantโœ… Yes
“Has-a” relationshipโŒ Use composition
Shared utility functionsโŒ Use functions
3+ levels deepโš ๏ธ Prefer composition

Real-World Example: Web Components

// Base UI component
class Component {
    constructor(element) {
        this.element = element;
        this.state = {};
    }

    setState(newState) {
        this.state = { ...this.state, ...newState };
        this.render();
    }

    render() {
        // Override in subclasses
    }
}

class Button extends Component {
    constructor(element, label) {
        super(element);
        this.state = { label, disabled: false };
    }

    render() {
        this.element.textContent = this.state.label;
        this.element.disabled = this.state.disabled;
    }

    disable() {
        this.setState({ disabled: true });
    }
}

Pro Tip: Class inheritance is a powerful tool for modeling “is-a” relationships. Use it when:

  • A subclass is a more specific version of the parent
  • You want to reuse parent behavior
  • You need polymorphism (same method, different behavior)

Key rules:

  • Use extends to inherit
  • Call super() first in subclass constructors
  • Use super.method() to call parent methods
  • Use instanceof to check types
  • Override to replace behavior; extend to add behavior

But remember: Don’t overuse inheritance! Composition is often better for “has-a” relationships. For 3+ level hierarchies, consider composition or mixins. And for utility functions, use plain functions instead of classes.


Stop using slow, ad-bloated tool sites! ๐Ÿคฎ

๐Ÿ”Ž Search “KandZ Tools” on Google to use many professional utilities for free.

KandZ.me is the ultimate minimalist hub for:
โœ… Finance (Mortgage, Interest, Inflation)
โœ… Tech (Base64, JSON, Dev Suite, IP)
โœ… Health (BMI, BMR, TDEE)
โœ… Productivity (Timer, Workspace, QR)

โšก๏ธ Fast & Private
๐Ÿ”’ No data leaves your device
๐Ÿ’Ž 100% Free

๐Ÿ”— Use it now: https://tools.kandz.me
๐Ÿ”– Bookmark itโ€”youโ€™ll need it later!

Similar Posts

Leave a Reply