25. Inheritance
Inheritance is the mechanism where a child class (subclass) inherits properties and methods from a parent class (superclass). This enables code reuse and the formation of logical hierarchies.
Why Is Inheritance Important?
Imagine a campus has many roles: Students, Lecturers, Staff. All of them have the properties name, email, and the method getInfo(). Instead of rewriting everything, we create a User class as the parent and inherit from it.
// Without inheritance — duplicate code
class Student {
constructor(name, email) { this.name = name; this.email = email; }
getInfo() { return `${this.name} - ${this.email}`; }
}
class Lecturer {
constructor(name, email) { this.name = name; this.email = email; }
getInfo() { return `${this.name} - ${this.email}`; }
}
// With inheritance — reusable code
class User {
constructor(name, email) { this.name = name; this.email = email; }
getInfo() { return `${this.name} - ${this.email}`; }
}
class Student extends User {}
class Lecturer extends User {}
Code Example
extends and super
class User {
constructor(name, email) {
this.name = name;
this.email = email;
this.registrationDate = new Date();
}
getInfo() {
return `${this.name} (${this.email})`;
}
getRegistrationDateFormat() {
return this.registrationDate.toLocaleDateString("en-US");
}
}
class Student extends User {
constructor(name, email, studentId, major) {
super(name, email); // call the parent constructor
this.studentId = studentId;
this.major = major;
this.gpa = 0;
this.courseList = [];
}
getInfo() {
return `${super.getInfo()} | StudentID: ${this.studentId} | ${this.major}`;
}
enrollInCourse(courseName) {
this.courseList.push(courseName);
return ` enrolls in `;
}
}
const student = new Student(
"Mike Johnson", "[email protected]", "2024001", "Computer Science"
);
console.log(student.getInfo());
// "Mike Johnson ([email protected]) | StudentID: 2024001 | Computer Science"
console.log(student.getRegistrationDateFormat()); // "14/7/2026"
Multi-Level Inheritance
class User {
constructor(name, email) {
this.name = name;
this.email = email;
}
getInfo() {
return `${this.name} <${this.email}>`;
}
getRole() {
return "User";
}
}
class Student extends User {
constructor(name, email, studentId) {
super(name, email);
this.studentId = studentId;
this.gpa = 0;
this.status = "Active";
}
getRole() {
return "Student";
}
getTranscript() {
return `Transcript: ${this.name} - GPA: ${this.gpa}`;
}
}
class StudentReguler extends Student {
constructor(name, email, studentId, myClass) {
super(name, email, studentId);
this.myClass = myClass;
this.type = "Reguler";
}
getRole() {
return "Student Reguler";
}
getJadwal() {
return `Class ${this.myClass}: Monday-Thursday`;
}
}
class StudentGraduate extends Student {
constructor(name, email, studentId, studyProgram) {
super(name, email, studentId);
this.studyProgram = studyProgram;
this.type = "Graduate";
this.researchStatus = "Active";
}
getRole() {
return "Graduate Student";
}
getResearchStatus() {
return `${this.name} - Status: ${this.researchStatus}`;
}
}
// Usage
const reguler = new StudentReguler(
"Mike", "[email protected]", "2024001", "CS-A"
);
const graduateStudent = new StudentGraduate(
"Dr. Anna", "[email protected]", "P2024001", "M.S. Computer Science"
);
console.log(reguler.getRole()); // "Student Reguler"
console.log(reguler.getJadwal()); // "Class CS-A: Monday-Thursday"
console.log(reguler.getInfo()); // inherited from User
console.log(graduateStudent.getRole()); // "Graduate Student"
console.log(graduateStudent.getTranscript()); // inherited from Student
Method Overriding
class Lecturer extends User {
constructor(name, email, nidn, course) {
super(name, email);
this.nidn = nidn;
this.course = course || [];
this.consultationSchedule = [];
}
// Override getRole()
getRole() {
return "Lecturer";
}
// Override getInfo() — add lecturer info
getInfo() {
return `Dr. ${super.getInfo()} | NIDN: ${this.nidn}`;
}
addConsultationSchedule(day, time) {
this.consultationSchedule.push({ day, time });
return `Consultation added: ${day} ${time}`;
}
// Static method
static dariData(data) {
return new Lecturer(data.name, data.email, data.nidn, data.mk);
}
}
const lecturerData = {
name: "John Smith",
email: "[email protected]",
nidn: "0012345678",
mk: ["Database", "Networking"]
};
const lecturer = Lecturer.dariData(lecturerData);
console.log(lecturer.getInfo());
// "Dr. John Smith <[email protected]> | NIDN: 0012345678"
console.log(lecturer.getRole()); // "Lecturer"
instanceof — Checking the Inheritance Type
const user = new User("Test", "[email protected]");
const student = new StudentReguler("Mike", "[email protected]", "001", "CS-A");
console.log(student instanceof StudentReguler); // true
console.log(student instanceof Student); // true
console.log(student instanceof User); // true
console.log(user instanceof Student); // false
Inheritance with Built-in Classes
class GradeList extends Array {
constructor(studentName) {
super();
this.studentName = studentName;
}
getAverage() {
if (this.length === 0) return 0;
const total = this.reduce((sum, v) => sum + v, 0);
return (total / this.length).toFixed(2);
}
getHighest() {
return Math.max(...this);
}
getLowest() {
return Math.min(...this);
}
getFormat() {
return this.map((v, i) => `Semester ${i + 1}: ${v}`).join(", ");
}
}
const gradeMike = new GradeList("Mike Johnson");
gradeMike.push(3.5);
gradeMike.push(3.8);
gradeMike.push(3.9);
console.log(gradeMike.length); // 3 (method from Array)
console.log(gradeMike.getAverage()); // "3.73"
console.log(gradeMike.getFormat()); // "Semester 1: 3.5, Semester 2: 3.8, ..."
Code Explanation
| Concept | Explanation |
|---|---|
extends |
Declares a child class that inherits from a parent |
super() |
Calls the parent constructor/method — required in the child constructor |
super.method() |
Calls the parent method from inside an overriding method |
| Overriding | The child defines a method with the same name → replaces the parent's |
instanceof |
Checks whether an object is an instance of a given class (including parent classes) |
Inheritance Hierarchy at a Campus
User (base)
├── Student
│ ├── StudentReguler
│ └── StudentGraduate
├── Lecturer
│ ├── PermanentFaculty
│ └── PracticumFaculty
└── Staff
├── StaffAdmin
└── StaffLab
Real-World Examples
An academic system with different roles:
class User {
constructor(name, email) {
this.name = name;
this.email = email;
}
getInfo() {
return `${this.name} <${this.email}>`;
}
}
class Student extends User {
constructor(name, email, studentId, major) {
super(name, email);
this.studentId = studentId;
this.major = major;
this.coursesTaken = [];
this.gradePerCourse = {};
}
enrollInCourse(course) {
if (this.coursesTaken.length >= 6) {
return "Maximum of 6 courses!";
}
this.coursesTaken.push(course);
return `${course} enrolled`;
}
inputGrade(course, grade) {
this.gradePerCourse[course] = grade;
}
calculateGPA() {
const gradeArray = Object.values(this.gradePerCourse);
if (gradeArray.length === 0) return 0;
return (gradeArray.reduce((a, b) => a + b, 0) / gradeArray.length).toFixed(2);
}
getTranscript() {
let transcript = `\n=== Transcript: ${this.name} (${this.studentId}) ===\n`;
for (const [mk, grade] of Object.entries(this.gradePerCourse)) {
transcript += ` ${mk}: ${grade}\n`;
}
transcript += ` GPA: ${this.calculateGPA()}\n`;
return transcript;
}
}
// Usage
const mike = new Student("Mike", "mike.edu", "2024001", "CS");
mike.enrollInCourse("Algorithms");
mike.enrollInCourse("Web Programming");
mike.enrollInCourse("Database");
mike.inputGrade("Algorithms", 3.8);
mike.inputGrade("Web Programming", 3.5);
mike.inputGrade("Database", 3.9);
console.log(mike.getTranscript());
// === Transcript: Mike (2024001) ===
// Algorithms: 3.8
// Web Programming: 3.5
// Database: 3.9
// GPA: 3.73
Conclusion
extendsconnects a child to a parent — the child inherits all methods and properties.super()must be called in the child constructor before usingthis.- Method overriding lets a child replace a parent method's behavior.
- Multi-level inheritance allows chains:
User → Student → StudentReguler. - Use
instanceofto check an object's type within an inheritance hierarchy.