Intermediate · Scope, this, prototypes and classes · topic 25 of 61 · 25 min
Inheritance and composition
Explanation
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.
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); // trueOverriding 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
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.
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| Question | Choose |
|---|---|
| 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 |
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
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.
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)
Write a class Dog that extends Animal and overrides speak() to return "<name> barks".
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().
Write a class ValidationError extends Error. new ValidationError("Bad PIN", "pin") must have name "ValidationError", message "Bad PIN" and field "pin".
Quick quiz
Read more (free)
Related help
Before this, learn
This topic builds on these. If something here feels new, open them first.
Related topics
- Inheritance and compositionPython Programming · Object-oriented programming
- Inheritance with extendsJava Programming (Core to Spring Boot) · Inheritance, polymorphism and interfaces
- Inheritance and interfacesKotlin and Android App Development · Classes, objects and collections
- Inheritance: building on an existing classC++ Programming (modern C++ and DSA) · Operator overloading, inheritance and polymorphism
- Inheritance, interfaces, mixins and extensionsFlutter and Dart · Null safety and object-oriented Dart
- Inheritance: base and derived classesC# and .NET · Inheritance, interfaces and records
Questions people ask about this
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.
What does super(…) do in a constructor?Related
Answer: Calls the parent class constructor
It initialises the parent part of the object.
How many classes can a Kotlin class extend?Related
Which relationship should inheritance model?Related
Answer: is-a
Public inheritance means the derived object can be used wherever the base is expected.
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
- This is the last topic of “Scope, this, prototypes and classes”. The module exam comes next.
- Module 5 exam: Scope, this, prototypes and classes · 12 questions · 25 min, without help. 5 topics of this module still to finish first.
- Then the next module, Modules, errors, JSON and dates. 61 topics left in the course before the final exam.