JavaScript Inheritance

In the previous lesson, we learned how a constructor sets up each object when a class is created. Now let’s see how one class can build on another using inheritance.

🧬 What is Inheritance?

Inheritance lets one class build on another. The class that gives away its features is the parent class, and the class that receives them is the child class. The child inherits the parent’s properties and methods, so you do not have to write them again.

You set up inheritance with the extends keyword. The child class lists the parent it extends, and from that point it owns everything the parent has.

inheritance.js
class Animal {
constructor(name) {
this.name = name;
}
eat() {
console.log(`${this.name} is eating.`);
}
}
class Dog extends Animal {}
const rex = new Dog("Rex");
rex.eat(); // Rex is eating.

Let’s walk through what each line does:

  • class Animal defines the parent class with a name property and an eat() method.
  • class Dog extends Animal {} makes Dog a child of Animal. The extends keyword is what links the two, so Dog automatically owns everything Animal has, even with an empty body.
  • const rex = new Dog("Rex") creates a Dog object. Since Dog has no constructor, JavaScript uses Animal’s constructor and sets this.name to "Rex".
  • rex.eat() calls a method Dog never defined. JavaScript looks up to the parent, finds eat() on Animal, and runs it. That is inheritance: the child gets the parent’s abilities for free.

🏗️ Calling the Parent with super()

When the child class needs its own constructor, it must call the parent constructor first. The super() function runs the parent’s constructor so the inherited properties are set up correctly.

inheritance.js
class Animal {
constructor(name) {
this.name = name;
}
eat() {
console.log(`${this.name} is eating.`);
}
}
class Dog extends Animal {
constructor(name, breed) {
super(name); // runs Animal's constructor and sets this.name
this.breed = breed; // Dog's own property
}
}
const rex = new Dog("Rex", "Labrador");
console.log(rex.name); // Rex
console.log(rex.breed); // Labrador

Let’s trace the constructor step by step:

  • constructor(name, breed) gives Dog its own constructor that accepts two values.
  • super(name) calls Animal’s constructor and passes name up to it. Animal then runs this.name = name, so the inherited property is set.
  • this.breed = breed adds a property that belongs only to Dog. We can only write this after super() has finished building the object.
  • new Dog("Rex", "Labrador") runs both steps, so rex.name reads "Rex" from the parent and rex.breed reads "Labrador" from the child.

The child reuses the parent’s setup with super() and then extends it with its own property.

super() must come first

Inside a child constructor, super() has to run before you touch this. JavaScript will not let you use this until the parent constructor has finished building the object.

🐕 Adding and Overriding Methods

A child class is not limited to what it inherits. It can add brand new methods, and it can override a parent method by defining one with the same name.

inheritance.js
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a sound.`);
}
}
class Dog extends Animal {
constructor(name, breed) {
super(name);
this.breed = breed;
}
// New method that Animal does not have
fetch() {
console.log(`${this.name} fetches the ball.`);
}
// Override: replaces Animal's speak()
speak() {
console.log(`${this.name} barks.`);
}
}
const rex = new Dog("Rex", "Labrador");
rex.fetch(); // Rex fetches the ball.
rex.speak(); // Rex barks.

Let’s see how the child changes the parent’s behavior:

  • super(name) still runs first to set up the inherited name property, then this.breed = breed adds the child’s own property.
  • fetch() is a brand new method that Animal does not have, so it belongs only to Dog.
  • speak() has the same name as the method in Animal. Defining it again overrides the parent version, so the child’s speak() wins.
  • rex.fetch() runs the new method, and rex.speak() runs the overridden one, printing Rex barks. instead of the parent’s message.

Overriding means the more specific class replaces the general behavior with its own.

♻️ Why Inheritance Reduces Duplication

Without inheritance, every class repeats the same shared code. Picture a Dog, a Cat, and a Bird that all need a name and an eat() method. Writing that code three times means three places to fix when something changes.

With inheritance you write the shared parts once in Animal, then let each child extend it.

inheritance.js
class Animal {
constructor(name) {
this.name = name;
}
eat() {
console.log(`${this.name} is eating.`);
}
}
class Cat extends Animal {
speak() {
console.log(`${this.name} meows.`);
}
}
class Bird extends Animal {
speak() {
console.log(`${this.name} chirps.`);
}
}

Let’s see how the shared code stays in one place:

  • class Animal holds the name property and the eat() method that every animal needs, written only once.
  • class Cat extends Animal reuses Animal’s name and eat(), then adds its own speak() that meows.
  • class Bird extends Animal does the same, but its speak() chirps instead.
  • Neither child rewrites name or eat(). Each one only writes the part that makes it different.

Less repeated code means fewer bugs and one clear place to make changes.

⚠️ Common Mistakes to Avoid

Mistake Problem Solution
Forgetting super() in the child constructor JavaScript throws a ReferenceError when you use this Call super(...) as the first line of the constructor
Using this before super() The object is not built yet, so this is unavailable Always run super() before any this.something = ...
Overriding a method by accident A child method with the same name silently replaces the parent’s Use a different name, or call super.method() to keep the parent behavior

Reuse the parent inside an override

Inside an overriding method you can still reach the parent version with super.speak(). That lets you run the parent’s behavior and then add to it, instead of replacing it completely.

🔧 Try It Yourself!

  1. Create a parent class Animal with a name property and an eat() method.
  2. Create a child class Dog that extends Animal and calls super(name) in its constructor.
  3. Add a new breed property to Dog after the super() call.
  4. Add a fetch() method to Dog and override the parent’s speak() method.
  5. Create a Dog object and call the inherited, the new, and the overridden methods to see each one work.

🧩 What You’ve Learned

  • ✅ Inheritance lets a child class build on a parent class with extends
  • ✅ The child inherits the parent’s properties and methods
  • super() calls the parent constructor and must run before this
  • ✅ A child can add new methods and override parent methods
  • ✅ Inheritance keeps shared code in one place and reduces duplication

🚀 What’s Next?

Now that classes can share behavior, we will learn how to protect the data inside them. Let’s continue to Encapsulation.

Share & Connect