Magento 2 Experten — Hyvä Theme, Tailwind CSS & SEO aus einer Hand ›

Inheritance and Prototypes in JavaScript

Inheritance and Prototypes in JavaScript

~15 Min. Lesezeit Zuletzt aktualisiert am August 8, 2026

Let's extend our account system with a SPECIALIZED account type – a savings account with interest – and along the way, learn what class/extends ACTUALLY does under the hood: JavaScript's prototype system.

extends and super

src/savingsAccount.js
import { Account } from './account.js';

export class SavingsAccount extends Account {
  constructor(name, startingBalance, interestRate) {
    super(name, startingBalance); // calls Account's constructor - REQUIRED before 'this'!
    this.interestRate = interestRate;
  }

  creditYearlyInterest() {
    const interest = this.balance * (this.interestRate / 100);
    this.record('Yearly interest', interest, 'Interest'); // 'record' INHERITED from Account
    return interest;
  }

  formatBalance() {
    return `${super.formatBalance()} (${this.interestRate}% interest)`; // OVERRIDE + call base behavior
  }
}
src/index.js
import { SavingsAccount } from './savingsAccount.js';

const savings = new SavingsAccount('Money Market', 5000, 2.5);
savings.creditYearlyInterest();

console.log(savings.formatBalance()); // 'Money Market: 5125.00 EUR (2.5% interest)'
console.log(savings instanceof Account);   // true - SavingsAccount IS-A Account

super(...) in the constructor calls the BASE class's constructor – required BEFORE this may be used in a derived constructor. super.formatBalance() inside an overridden method calls the base class's ORIGINAL implementation, instead of replacing it entirely.

What class REALLY is: the prototype system

JavaScript has NO class-based inheritance in the sense of Java or C# – class is "syntactic sugar" over an older, MORE DYNAMIC mechanism: the prototype chain. Every object has an internal link to another object, its "prototype" – if a property is missing on the object itself, JavaScript automatically keeps looking along this chain:

function OldAccount(name, balance) {
  this.name = name;
  this.balance = balance;
}

// Define methods on the PROTOTYPE instead of on every instance:
OldAccount.prototype.formatBalance = function () {
  return `${this.name}: ${this.balance.toFixed(2)} EUR`;
};

const account = new OldAccount('Checking', 1500);
console.log(account.formatBalance()); // 'Checking: 1500.00 EUR'
// 'account' has NO own 'formatBalance' property -
// JavaScript finds it via the prototype chain on OldAccount.prototype

This is EXACTLY the same pattern class automatically creates for us – methods defined in a class body land internally on the class's prototype, not on every single instance. This also explains why methods are shared MEMORY-EFFICIENTLY: only ONE copy of each method exists, no matter how many Account instances are created.

The prototype chain with extends

console.log(Object.getPrototypeOf(savings) === SavingsAccount.prototype); // true
console.log(Object.getPrototypeOf(SavingsAccount.prototype) === Account.prototype); // true

console.log(savings instanceof SavingsAccount); // true
console.log(savings instanceof Account);        // true - found via the chain
console.log(savings instanceof Object);         // true - EVERY object ends up here eventually

Tipp: For everyday use, knowing class/extends/super is enough – but the prototype knowledge from this section explains WHY JavaScript behaves this way, and helps in understanding error messages like "X is not a function" (the method exists neither on the object nor anywhere in its prototype chain).

Polymorphism: same method, different behavior

src/index.js
const accounts = [
  new Account('Checking', 1500),
  new SavingsAccount('Money Market', 5000, 2.5),
];

for (const account of accounts) {
  // EACH account calls ITS OWN version of formatBalance() - polymorphism
  console.log(account.formatBalance());
}
// 'Checking: 1500.00 EUR'
// 'Money Market: 5000.00 EUR (2.5% interest)'