Skip to content

Intermediate · Scope, this, prototypes and classes · topic 25 of 61 · 25 min

Inheritance and composition

Explanation

A class can extend another class to reuse and specialise it: the child calls super() in its constructor and can override methods, calling super.method() to reuse the parent's version. Inheritance models "is-a" relationships; for "has-a" relationships, composition (putting objects inside objects) is usually simpler and more flexible.

extends and super

Inheritance lets a new class (the child or subclass) start from an existing class (the parent or superclass). The child gets all the parent's methods and can add or change some. In the constructor, the child must call super(...) before using this, so the parent can set up its part.

javascript
class Account {
  constructor(owner, balance) {
    this.owner = owner;
    this.balance = balance;
  }
  withdraw(amount) {
    if (amount > this.balance) return false;
    this.balance -= amount;
    return true;
  }
  describe() { return `${this.owner}: ₹${this.balance}`; }
}

class SavingsAccount extends Account {
  constructor(owner, balance, rate) {
    super(owner, balance);   // must come before using this
    this.rate = rate;
  }
  addInterest() {
    this.balance += Math.round(this.balance * this.rate / 100);
  }
  describe() {                       // override
    return `${super.describe()} (savings, ${this.rate}%)`;
  }
}
const s = new SavingsAccount('Ravi', 10000, 4);
s.addInterest();
console.log(s.describe());           // Ravi: ₹10400 (savings, 4%)
console.log(s.withdraw(400), s.balance); // true 10000 (inherited method)
console.log(s instanceof Account);   // true
Careful: Forgetting super() in a child constructor, or using this before it, throws ReferenceError: Must call super constructor in derived class before accessing 'this'. If the child does not need its own constructor, leave it out completely; JavaScript then passes all arguments to the parent automatically.

Overriding and super.method()

If the child defines a method with the same name, the child's version is used (it shadows the parent's on the prototype chain). Inside it, super.method() calls the parent's version, so you can extend behaviour instead of copying it.

Extending Error

javascript
class PaymentError extends Error {
  constructor(message, code) {
    super(message);
    this.name = 'PaymentError';
    this.code = code;
  }
}
try {
  throw new PaymentError('Card declined', 'DECLINED');
} catch (e) {
  console.log(e instanceof PaymentError, e.name, e.code, e.message);
  // true PaymentError DECLINED Card declined
}

Composition: has-a instead of is-a

Inheritance fits when the child truly IS a kind of the parent: a SavingsAccount is an Account. Deep inheritance trees (Vehicle → Car → ElectricCar → SelfDrivingElectricCar) become fragile, because a change high up breaks everything below. Composition builds an object out of smaller parts it HAS: a Car has an Engine and has a GPS.

javascript
const withLogger = (name) => ({ log: (msg) => `[${name}] ${msg}` });
const withNotifier = () => ({ notify: (to) => `SMS sent to ${to}` });

function createOrderService() {
  return { ...withLogger('orders'), ...withNotifier() };
}
const svc = createOrderService();
console.log(svc.log('placed'));      // [orders] placed
console.log(svc.notify('98xxxxxx10')); // SMS sent to 98xxxxxx10
Mixing small capability objects together is called a mixin pattern.
QuestionChoose
Is B truly a kind of A, sharing most behaviour?Inheritance (class B extends A)
Does B just need some ability of A?Composition (B has an A)
Would the tree be more than 2–3 levels deep?Composition
Think of it like this: Inheritance is like a family surname: a child inherits it automatically and cannot easily drop it. Composition is like assembling a team: you pick a cook, a driver and an accountant for the job, and swap any of them later.
Tip: The well-known advice "favour composition over inheritance" does not mean never inherit. Use extends for small, stable "is-a" relationships, such as custom error classes.

Need help?

Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.

Try:

Watch the lesson

Inheritance and composition · 1/6

Inheritance and composition

In this lesson you will build classes on top of other classes, and learn when not to.

Prefer a video by a teacher? Find free videos on “javascript class inheritance extends super composition” on YouTube ↗

In real life: Notifications in a delivery app

A delivery app sends SMS, email and push notifications. All share a common send flow (validate, format, log), so they extend a Notification base class and override only the format and the channel. The order service, in turn, HAS a notifier inside it (composition), so tests can swap in a fake one.

javascript
class Notification {
  send(to, text) { return `${this.channel()} → ${to}: ${this.format(text)}`; }
  format(text) { return text; }
}
class Sms extends Notification {
  channel() { return 'SMS'; }
  format(text) { return text.slice(0, 160); }
}
console.log(new Sms().send('98xxxxxx10', 'Your order is out for delivery'));

Practice (0/3 done)

Task 1 · Code · Javascript

Write a class Dog that extends Animal and overrides speak() to return "<name> barks".

Task 2 · Code · Javascript

Write a class FixedDeposit extends Account. Its constructor(owner, balance, years) must call super and store years. Override describe() to add " for <years> years" to the parent's description using super.describe().

Task 3 · Code · Javascript

Write a class ValidationError extends Error. new ValidationError("Bad PIN", "pin") must have name "ValidationError", message "Bad PIN" and field "pin".

Quick quiz

Question 1

1.In a child class constructor, what must happen before using this?

Question 2

2.Inside an overriding method, how do you call the parent version?

Question 3

3.Which relationship suits composition best?

Question 4

4.class B extends A {} (no constructor). What does new B(1, 2) do?

Read more (free)

Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.

In a child class constructor, what must happen before using this?

Answer: Call super()

The parent part must be initialised first with super().

Inside an overriding method, how do you call the parent version?

Answer: super.method()

super.method() calls the method from the parent class.

Which relationship suits composition best?

Answer: A Car has an Engine

"Has-a" relationships are modelled by holding the part inside.

class B extends A {} (no constructor). What does new B(1, 2) do?

Answer: Calls A's constructor with 1, 2

A missing constructor in a subclass passes all arguments to super automatically.

Which relationship fits composition best?Related

Answer: A Library has Books

"Has a" relationships are modelled by holding other objects as attributes.

From Inheritance and composition

What does super(…) do in a constructor?Related

Answer: Calls the parent class constructor

It initialises the parent part of the object.

From Inheritance with extends

How many classes can a Kotlin class extend?Related

Answer: One

One superclass, but many interfaces.

From Inheritance and interfaces

Which relationship should inheritance model?Related

Answer: is-a

Public inheritance means the derived object can be used wherever the base is expected.

From Inheritance: building on an existing class

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

Next steps

  1. This is the last topic of “Scope, this, prototypes and classes”. The module exam comes next.
  2. Module 5 exam: Scope, this, prototypes and classes · 12 questions · 25 min, without help. 5 topics of this module still to finish first.
  3. Then the next module, Modules, errors, JSON and dates. 61 topics left in the course before the final exam.

← Previous: Classes