Inheritance & The super Keyword

Inheritance lets one class borrow everything from another class, so you don't repeat yourself. super is the tool you use to talk to the parent class.

What Is Inheritance?

Imagine you have a class called Animal that knows how to eat and sleep. Now you want a Dog class. A dog can also eat and sleep — plus it can bark. Instead of writing eat and sleep again inside Dog, you can just say "Dog inherits from Animal" and only write the new stuff.

That is inheritance — a child class automatically gets everything the parent class has.

👨‍👧 Real-life analogy

Think of a parent and child. A child inherits traits from the parent — eye color, height, etc. But the child can also have their own unique traits. In programming, a child class inherits methods and properties from the parent class, and can also add or change things.

The extends Keyword

You use extends to say "this class is a child of that class."

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

  eat() {
    return `${this.name} is eating.`;
  }

  sleep() {
    return `${this.name} is sleeping.`;
  }
}

class Dog extends Animal {
  bark() {
    return `${this.name} says woof!`;
  }
}

const rex = new Dog("Rex");

rex.eat();   // "Rex is eating."   ← inherited from Animal
rex.sleep(); // "Rex is sleeping." ← inherited from Animal
rex.bark();  // "Rex says woof!"   ← Dog's own method
  • class Dog extends Animal — Dog is the child class; Animal is the parent (also called "base class" or "superclass")
  • Dog has no constructor here — JavaScript automatically uses Animal's constructor
  • rex.eat() works even though eat is defined in Animal, not Dog
  • this.name inside bark() works because the Animal constructor set it up

The super() Call — Running the Parent Constructor

When a child class has its own constructor, it must call super() first before using this. super() runs the parent class's constructor so the shared setup happens.

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

class Dog extends Animal {
  constructor(name, breed) {
    super(name);       // ← must come first! runs Animal's constructor
    this.breed = breed; // ← now we can use this
  }
}

const rex = new Dog("Rex", "Labrador");
console.log(rex.name);  // "Rex"      ← set by Animal constructor via super
console.log(rex.alive); // true       ← set by Animal constructor via super
console.log(rex.breed); // "Labrador" ← set by Dog constructor
  • super(name) — calls Animal's constructor with the name argument
  • This sets up this.name and this.alive inside the new object
  • Only after super() can you safely use this in the child constructor
  • If you skip super(), JavaScript throws a ReferenceError
⚠ Rule: super() must come before this

In any child class constructor, you cannot use this before calling super(). JavaScript will throw a ReferenceError: Must call super constructor in derived class before accessing 'this'.

// ❌ Wrong — this before super
class Dog extends Animal {
  constructor(name, breed) {
    this.breed = breed; // ReferenceError!
    super(name);
  }
}

// ✅ Correct — super first
class Dog extends Animal {
  constructor(name, breed) {
    super(name);        // always first
    this.breed = breed; // safe now
  }
}

super.method() — Calling a Parent Method

Inside a child class method, super.methodName() lets you call the same method from the parent class. This is useful when you want to extend what the parent does, not completely replace it.

class Animal {
  describe() {
    return `I am ${this.name}`;
  }
}

class Dog extends Animal {
  describe() {
    const parentDesc = super.describe(); // calls Animal's describe()
    return `${parentDesc} and I am a dog.`;
  }
}

const rex = new Dog("Rex");
rex.describe(); // "I am Rex and I am a dog."
  • super.describe() — runs Animal's describe() method and returns its result
  • Dog's describe() adds to the parent's result instead of replacing it entirely
  • This pattern — call parent, then add more — is very common

Method Overriding

When a child class defines a method with the same name as the parent, the child's version wins. This is called overriding.

class Animal {
  speak() {
    return "...";
  }
}

class Dog extends Animal {
  speak() {
    return "Woof!"; // overrides Animal's speak()
  }
}

class Cat extends Animal {
  speak() {
    return "Meow!"; // overrides Animal's speak()
  }
}

const d = new Dog();
const c = new Cat();

d.speak(); // "Woof!"
c.speak(); // "Meow!"

Each class can have its own behavior for the same method name. This is called polymorphism — a fancy word that just means "same method name, different behavior depending on the object."

Multi-Level Inheritance

A child class can itself be a parent. You can chain as many levels as you need (but try not to go too deep — it gets hard to follow).

class Animal {
  constructor(name) { this.name = name; }
  eat() { return `${this.name} eats.`; }
}

class Dog extends Animal {
  constructor(name, breed) {
    super(name);
    this.breed = breed;
  }
  bark() { return "Woof!"; }
}

class Puppy extends Dog {
  constructor(name, breed, toyName) {
    super(name, breed);      // runs Dog's constructor (which runs Animal's)
    this.toyName = toyName;
  }
  play() { return `${this.name} plays with ${this.toyName}.`; }
}

const p = new Puppy("Buddy", "Beagle", "ball");
p.eat();  // "Buddy eats."         ← from Animal
p.bark(); // "Woof!"               ← from Dog
p.play(); // "Buddy plays with ball." ← from Puppy

The instanceof Operator

instanceof checks whether an object was created from a specific class (or any class in its inheritance chain). It returns true or false.

class Animal {}
class Dog extends Animal {}
class Cat extends Animal {}

const rex = new Dog();

rex instanceof Dog;    // true  — rex is a Dog
rex instanceof Animal; // true  — Dog extends Animal, so rex is also an Animal
rex instanceof Cat;    // false — rex is not a Cat
  • obj instanceof ClassName — returns true if obj was made from ClassName or any class that extends it
  • Useful for checking what kind of object you're dealing with before calling methods on it
  • Works all the way up the chain — a Puppy is also an Animal
💡 Practical use of instanceof
function makeSpeak(animal) {
  if (animal instanceof Dog) {
    console.log("Woof!");
  } else if (animal instanceof Cat) {
    console.log("Meow!");
  } else {
    console.log("...");
  }
}

Checking the Prototype Chain

Under the hood, inheritance in JavaScript works through something called the prototype chain. You don't need to understand all the details yet, but here are two handy tools:

class Animal {}
class Dog extends Animal {}

const rex = new Dog();

// Check what class created an object
rex.constructor.name; // "Dog"

// Check what class Dog extends
Object.getPrototypeOf(Dog) === Animal; // true

// Check if a method exists anywhere in the chain
"eat" in rex; // true (if Animal has eat())

What You Cannot Do

⚠ Limitations of inheritance
  • No multiple inheritance — a class can only extend one parent class. class Dog extends Animal, Mammal is not valid JavaScript.
  • Don't go too deep — chains like A → B → C → D → E get very hard to debug. If you need more than 2–3 levels, consider a different design.
  • Forgetting super() in a child constructor — always causes a ReferenceError.

Common Mistakes

⚠ Watch out for
  • Forgetting to pass arguments to super(). If the parent needs name, you must pass it: super(name), not just super().
  • Overriding a method but forgetting you needed the parent's logic too — use super.methodName() to keep it.
  • Using instanceof with plain objects ({}) — it returns false for all your classes because a plain object wasn't made with new YourClass().

Best Practices

  • Use inheritance when a child class truly is a type of the parent. A Dog is an Animal — good fit. A Car is not an Animal — bad fit.
  • Keep parent classes general and child classes specific.
  • Prefer shallow inheritance chains (1–2 levels). Deep chains are hard to follow and debug.
  • Always call super() at the top of a child constructor — before anything else.

Performance Notes

Inheritance in JavaScript uses the prototype chain internally. Method lookups travel up the chain — the deeper the chain, the slightly more work for each lookup. In practice this is almost never a real-world issue for typical class hierarchies.

Browser Compatibility

extends, super, and instanceof all work in every modern browser (Chrome, Firefox, Safari, Edge) and Node.js. They've been part of JavaScript since ES6 (2015).

Interview Questions

What does extends do?

It creates a parent-child relationship between two classes. The child class automatically inherits all properties and methods from the parent class, so you don't need to rewrite them.

Why must you call super() before using this in a child constructor?

The parent constructor sets up the foundation of the object (the this object). Until super() runs, this doesn't exist yet inside the child. JavaScript enforces this rule to ensure the object is fully set up before you start adding your own properties.

What is method overriding?

When a child class defines a method with the same name as a method in the parent class, the child's version replaces the parent's version for objects of that child class. The parent's version can still be called with super.methodName().

What does instanceof check?

It checks whether an object was created from a specific class, or any class that that class extends. It returns true if the object is anywhere in the inheritance chain of the given class.

✏️ Exercise

Create a Vehicle class with a make and model property and a describe() method. Then create a Car class that extends Vehicle, adds a doors property, and overrides describe() to include the number of doors.

🧠 Quiz

1. What keyword makes one class inherit from another?

extends.

2. What does super() do when called inside a constructor?

It runs the parent class's constructor, which sets up the shared properties on the new object.

3. If Dog extends Animal, is a Dog instance also an instance of Animal?

Yes. new Dog() instanceof Animal returns true.

🚀 Mini Challenge

Create three classes: Shape (with a color property and a describe() method), Circle (extends Shape, adds radius, overrides describe() to include area), and Rectangle (extends Shape, adds width and height, overrides describe() to include area). Use super.describe() inside the overrides.

Summary

  • extends makes a child class that inherits everything from a parent class.
  • super() in a constructor runs the parent constructor — must be called before this.
  • super.method() calls a parent class method from inside a child class method.
  • Method overriding lets a child class replace a parent's method with its own version.
  • instanceof checks if an object belongs to a class or any class it inherits from.

Related Topics

MDN reference: developer.mozilla.org → JavaScript → Classes → extends / super