Nach dieser Lektion bauen Sie eine Unterklasse mit extends, rufen den constructor der Elternklasse mit super() auf und überschreiben eine Methode, während Sie die Version der Elternklasse weiterverwenden.
Lektion 3 von 5 in I2 Objekte, Prototypen und Klassen
Sagen Sie es vorher, bevor Sie weiterlesen: Cat hat gar keinen Rumpf. Was gibt dieser Code aus?
class Animal {
constructor(name) {
this.name = name;
}
speak() {
return `${this.name} makes a sound`;
}
}
class Cat extends Animal {}
console.log(new Cat("Mia").speak());
Üben · Aufgabe 3 von 7
Der constructor von Animal speichert den Namen. Ergänzen Sie den Aufruf, der ihn aus dem constructor von Dog ausführt.
class Dog extends Animal {
constructor(name, breed) {
____(name);
this.breed = breed;
}
}
constructor(name, breed) {(name);
Üben · Aufgabe 4 von 7
Ordnen Sie jedem Stück Syntax zu, was es bewirkt.
Üben · Aufgabe 5 von 7
describe() steht nur in Animal. Was gibt dieser Code aus?
class Animal {
speak() {
return "...";
}
describe() {
return `It says ${this.speak()}`;
}
}
class Dog extends Animal {
speak() {
return "woof";
}
}
console.log(new Dog().describe());
Denksport · Aufgabe 6 von 7
Knobelaufgabe. B gibt vor und nach super() etwas aus. In welcher Reihenfolge erscheinen die Zeilen?
class A {
constructor() {
console.log("A starts");
}
}
class B extends A {
constructor() {
console.log("B starts");
super();
console.log("B ends");
}
}
new B();
Anwenden · Aufgabe 7 von 7
Kleine Aufgabe: Schreiben Sie eine Klasse Vehicle mit constructor(brand, wheels) und describe(), die einen Text wie "Brompton with 2 wheels" zurückgibt. Schreiben Sie dann ElectricCar extends Vehicle. Ihr constructor(brand, range) übergibt 4 Räder an super und speichert range; ihr describe() hängt mit super.describe() ", range 390 km" an den Text der Elternklasse an. Geben Sie beide Beschreibungen aus und prüfen Sie instanceof in beide Richtungen.
Prüfen Sie Ihr Ergebnis anhand dieser Liste
Selbst programmieren
Lesen Sie das ausgearbeitete Beispiel und lösen Sie dann die Übungen. Ihr Code läuft in Ihrem Browser oder auf Ihrem Computer und wird nie hochgeladen.
Ausgearbeitetes Beispiel
Animal, Dog und Puppy
Animal speichert einen Namen und hat speak() und describe(). Dog extends Animal: Sein constructor ruft zuerst super(name) auf, speichert dann die Rasse, und sein speak() überschreibt das von Animal. Puppy extends Dog ohne constructor und baut mit super.speak() auf dem speak() von Dog auf. describe() steht nur einmal, in Animal, und trotzdem beschreibt sich jedes Tier mit seinem eigenen speak.
main.js
class Animal {
constructor(name) {
this.name = name;
}
speak() {
return `${this.name} makes a sound`;
}
describe() {
return `${this.name}: ${this.speak()}`;
}
}
class Dog extends Animal {
constructor(name, breed) {
super(name); // runs Animal's constructor first
this.breed = breed;
}
speak() {
return `${this.name} barks`; // overrides Animal's speak
}
}
class Puppy extends Dog {
speak() {
return `${super.speak()} softly`; // builds on Dog's speak
}
}
const generic = new Animal("Something");
const rex = new Dog("Rex", "terrier");
const bello = new Puppy("Bello", "poodle");
console.log(generic.describe());
console.log(rex.describe());
console.log(bello.describe());
console.log(bello);
console.log(bello instanceof Puppy, bello instanceof Dog, bello instanceof Animal);
console.log(rex instanceof Puppy);
console.log(Object.getPrototypeOf(Dog.prototype) === Animal.prototype);
Ausführen mit
node main.js
Ausgabe
Something: Something makes a sound
Rex: Rex barks
Bello: Bello barks softly
Puppy { name: 'Bello', breed: 'poodle' }
true true true
false
true
describe() liegt in Animal, aber this.speak() fand die Überschreibung der Klasse des jeweiligen Objekts.
Puppy hat keinen constructor; der Standard-constructor reichte "Bello" und "poodle" an den von Dog weiter.
Ein Puppy ist ein Dog und ein Animal; ein einfacher Dog ist kein Puppy.
Dog.prototype verweist auf Animal.prototype: Das hat extends eingerichtet.
Ändern und ausführen
Tab rückt ein, Umschalt+Tab rückt aus. Um den Editor mit der Tastatur zu verlassen, drücken Sie Esc und dann Tab.
Beim ersten Ausführen lädt Ihr Browser den JavaScript-Runner herunter (bis zu 0.1 MB) und speichert ihn im Cache. Ihr Code läuft in der eigenen Engine Ihres Browsers und bleibt auf Ihrem Gerät.
Übungen
Übung 1 von 2
Ein Kreis ist eine Form
Shape speichert einen Namen, und sein describe() verwendet area(). Circle extends Shape: new Circle(2) soll sich als "circle with area 13" beschreiben. Der constructor im Starter speichert den Radius, ruft aber nie den constructor von Shape auf, deshalb wirft new Circle(2). Rufen Sie zuerst super("circle") auf.
Tab rückt ein, Umschalt+Tab rückt aus. Um den Editor mit der Tastatur zu verlassen, drücken Sie Esc und dann Tab.
Beim ersten Ausführen lädt Ihr Browser den JavaScript-Runner herunter (bis zu 0.1 MB) und speichert ihn im Cache. Ihr Code läuft in der eigenen Engine Ihres Browsers und bleibt auf Ihrem Gerät.
Hinweise
Hinweis 1
Führen Sie die Tests aus: Jeder scheitert mit einem ReferenceError. Was muss der constructor einer Unterklasse tun, bevor er this verwendet?
Hinweis 2
super(…) führt den constructor von Shape aus. Welchen Namen übergibt ein Kreis ihm?
Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.
export class Shape {
constructor(name) {
this.name = name;
}
area() {
return 0;
}
describe() {
return `${this.name} with area ${this.area()}`;
}
}
export class Circle extends Shape {
constructor(radius) {
super('circle');
this.radius = radius;
}
area() {
return Math.round(Math.PI * this.radius ** 2);
}
}
Auf dem eigenen Computer ausführen
Installieren Sie ECMAScript 2026 oder neuer. Speichern Sie diese Dateien in einem Ordner, öffnen Sie dort ein Terminal und führen Sie die Befehle unten aus.
main.js
export class Shape {
constructor(name) {
this.name = name;
}
area() {
return 0;
}
describe() {
return `${this.name} with area ${this.area()}`;
}
}
export class Circle extends Shape {
constructor(radius) {
this.radius = radius;
}
area() {
return Math.round(Math.PI * this.radius ** 2);
}
}
main.test.js
import {test} from 'node:test';
import assert from 'node:assert/strict';
import {Circle, Shape} from './main.js';
test('new Circle(2) hat den Namen circle und den Radius 2', () => {
const c = new Circle(2);
assert.deepEqual([c.name, c.radius], ['circle', 2], `Name und Radius sind ${c.name} und ${c.radius}`);
});
test('describe verwendet die Kreisfläche', () => {
const got = new Circle(2).describe();
assert.equal(got, 'circle with area 13', `describe() ergab ${got}`);
});
test('Ein Kreis ist eine Shape', () => {
assert.ok(new Circle(1) instanceof Shape, 'new Circle(1) sollte eine Instanz von Shape sein');
});
package.json
{
"type": "module"
}
package.json sagt Node.js, dass die .js-Dateien Module sind; lassen Sie die Datei im Ordner.
Programm ausführen:
node main.js
Prüfungen ausführen (learnrun.js muss im selben Ordner liegen):
Ein Manager ist ein Employee mit einem Team. new Manager("Ada", 5000, ["Max", "Mia"]).describe() soll "Ada earns 5000 EUR and leads 2 people" zurückgeben. Der Starter schreibt einen eigenen Text und verliert den Gehaltsteil. Verwenden Sie das describe() von Employee mit super.describe() wieder und hängen Sie den Team-Teil an.
Tab rückt ein, Umschalt+Tab rückt aus. Um den Editor mit der Tastatur zu verlassen, drücken Sie Esc und dann Tab.
Beim ersten Ausführen lädt Ihr Browser den JavaScript-Runner herunter (bis zu 0.1 MB) und speichert ihn im Cache. Ihr Code läuft in der eigenen Engine Ihres Browsers und bleibt auf Ihrem Gerät.
Hinweise
Hinweis 1
Führen Sie die Tests aus: Dem Text des Managers fehlt „earns 5000 EUR“. Welche Methode schreibt diesen Teil schon?
Hinweis 2
super.describe() ruft das describe von Employee auf, wobei this weiterhin der Manager ist.
Hinweis 3
return `${super.describe()} and leads ${this.team.length} people`;
Eine Lösung zeigen
Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.
Installieren Sie ECMAScript 2026 oder neuer. Speichern Sie diese Dateien in einem Ordner, öffnen Sie dort ein Terminal und führen Sie die Befehle unten aus.
class Animal {
constructor(name) {
this.name = name;
}
}
class Dog extends Animal {
constructor(name, breed) {
this.breed = breed;
super(name);
}
}
const rex = new Dog("Rex", "terrier");
console.log(rex.breed);
Was Node.js ausgibt
ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor
Warum, und die Lösung
In einer Unterklasse wird das Objekt, auf das this zeigt, vom constructor der Elternklasse eingerichtet; es existiert also nicht, bevor super() gelaufen ist. Rufen Sie super(name) als Erstes im constructor auf und setzen Sie dann this.breed. Derselbe Fehler kommt, wenn der constructor einer Unterklasse super() ganz vergisst.
this.method() in der eigenen Überschreibung aufrufen
class Animal {
speak() {
return "...";
}
}
class Dog extends Animal {
speak() {
return `${this.speak()} woof`;
}
}
console.log(new Dog().speak());
Was Node.js ausgibt
RangeError: Maximum call stack size exceeded
Warum, und die Lösung
this.speak() beginnt die Suche beim Hund und findet wieder das speak von Dog: Die Methode ruft sich endlos selbst auf, bis der Aufrufstapel voll ist. Um die Version der Elternklasse zu erreichen, schreiben Sie super.speak(), das die Suche bei Animal.prototype beginnt.
Ein Objekt statt einer Klasse erweitern
const animal = {
speak() {
return "...";
}
};
class Dog extends animal {}
console.log(new Dog().speak());
Was Node.js ausgibt
TypeError: Class extends value #<Object> is not a constructor or null
Warum, und die Lösung
extends braucht rechts eine Klasse oder eine Konstruktorfunktion, etwas, das sich mit new aufrufen lässt. animal ist ein gewöhnliches Objekt, wie in Lektion I2.1. Machen Sie daraus class Animal { speak() { … } } und schreiben Sie class Dog extends Animal, oder bleiben Sie bei Objekten und verwenden Object.create(animal).
JavaScript im Browser: die eigene Engine Ihres Browsers in einem abgeschotteten Worker. Syntaxfehler findet acorn 8.18.0, MIT. Lizenz und Quellcode
Abschlussquiz
5 Fragen, ohne Hinweise. Ab 80 % ist die Lektion abgeschlossen.
Erledigen Sie zuerst alle Aufgaben oben, um das Abschlussquiz freizuschalten.
Kernideen
extends und super()
class Dog extends Animal macht Dog zu einer Unterklasse von Animal: Ein Hund bekommt jede Methode von Animal und dazu seine eigenen. In einer Unterklasse richtet die Elternklasse das Objekt ein, deshalb muss der constructor super(…) mit den Argumenten der Elternklasse aufrufen, bevor er this anfasst. Code vor super() darf laufen, solange er this nicht verwendet. Verwenden Sie this zuerst oder vergessen super() ganz, wirft new einen ReferenceError. Eine Unterklasse ohne constructor bekommt einen Standard-constructor, der alle seine Argumente an super weiterreicht.
Überschreiben und super.method()
Eine Methode in der Unterklasse mit demselben Namen wie eine Methode der Elternklasse überschreibt sie: Die Suche findet zuerst die Version der Unterklasse. Das gilt auch, wenn eine Methode der Elternklasse this.speak() aufruft; bei einem Hund ist this der Hund, also läuft das speak des Hundes. Um auf der Methode der Elternklasse aufzubauen, statt sie zu ersetzen, rufen Sie in der Überschreibung super.speak() auf. Schreiben Sie dort stattdessen this.speak(), ruft die Überschreibung sich selbst auf, immer wieder, bis ein RangeError sie stoppt.
Die Kette einer Unterklasse
extends fügt ein Glied hinzu: Der Prototyp von Dog.prototype ist Animal.prototype, dessen Prototyp ist Object.prototype. So findet ein Hund die Methoden von Animal. instanceof prüft die ganze Kette, ein Puppy ist also auch ein Dog und ein Animal, ein einfacher Dog aber kein Puppy. extends braucht rechts eine Klasse oder Konstruktorfunktion; ein gewöhnliches Objekt wirft einen TypeError. Auch eingebaute Klassen wie Array oder Map lassen sich erweitern. In Modul I4 erweitern Sie Error, um eigene Fehlertypen zu bauen.