Menu

JavaScript Klassen: Konstruktor, Methoden & new

Wie Klassen in JavaScript wirklich funktionieren — Konstruktor, Methoden, Instanzfelder, Getter und Setter sowie das mentale Modell hinter dem class-Keyword.

Eine Klasse ist der Bauplan für Objekte

Eine JavaScript-Klasse beschreibt, wie ein bestimmter Objekttyp aussieht und was er kann. Du legst den Bauplan einmal an und kannst daraus anschließend beliebig viele Instanzen erzeugen. Jede Instanz hat ihre eigenen Daten, teilt sich aber die gleichen Methoden.

So sieht der grundsätzliche Aufbau aus:

index.js
Output
Click Run to see the output here.

class User { ... } definiert den Bauplan, new User(...) erzeugt daraus eine Instanz. Jede Instanz bekommt ihren eigenen name und ihre eigene email, aber beide teilen sich dieselbe greet-Methode, die einmal an der Klasse hängt.

Zwei Instanzen, zwei Datensätze, ein gemeinsamer Satz an Methoden. Mehr steckt im Grunde nicht dahinter.

Der constructor initialisiert jede Instanz

Der constructor ist eine spezielle Methode, die genau einmal pro Instanz läuft – nämlich in dem Moment, in dem new das Objekt erzeugt. Seine Aufgabe: das frische Objekt aufzusetzen, typischerweise indem er die übergebenen Argumente auf this schreibt:

index.js
Output
Click Run to see the output here.

this zeigt im Konstruktor auf die frisch erzeugte Instanz, die gerade entsteht. Mit this.x = x hängst du x genau an dieses Objekt. Jeder Aufruf von new Point(...) bekommt sein eigenes this – und damit auch sein eigenes x und y.

Wenn du keinen Konstruktor schreibst, spendiert dir JavaScript automatisch einen leeren. Du musst also nur dann selbst einen definieren, wenn es bei der Initialisierung wirklich etwas zu tun gibt.

Warum new der entscheidende Schalter ist

Ein Klassenaufruf ohne new führt direkt zu einem Fehler:

const p = Point(3, 4);
// TypeError: Class constructor Point cannot be invoked without 'new'

Das ist so gewollt. new erledigt vier Dinge, und zwar in dieser Reihenfolge:

  1. Es legt ein frisches, leeres Objekt an.
  2. Es verknüpft dieses Objekt mit dem Prototype der Klasse (dort liegen die Methoden).
  3. Es ruft den constructor auf, wobei this an das neue Objekt gebunden wird.
  4. Es gibt das neue Objekt zurück.

Ohne new passiert nichts davon. Die Klasse erzwingt diese Regel, damit du es nicht aus Versehen vergessen kannst – ein echter Fortschritt gegenüber der Zeit vor class, als ein vergessenes new stillschweigend das globale Objekt verunreinigt hat.

Methoden werden geteilt, Felder gehören zur Instanz

Methoden, die du im Klassenrumpf definierst, landen auf dem Prototype – eine einzige Kopie, die sich alle Instanzen teilen. Instanzfelder dagegen (alles, was du an this zuweist) existieren pro Instanz, also jedes Mal als eigene Kopie.

index.js
Output
Click Run to see the output here.

Jede Instanz hat ihr eigenes count – wenn du den einen Zähler hochzählst, bleibt der andere davon unberührt. Aber a.increment und b.increment sind buchstäblich dieselbe Funktion: Sie liegt nur einmal auf dem Prototype und wird bei jedem Aufruf über die Instanz von dort geholt. Genau deshalb skalieren Klassen so günstig – bei tausend Instanzen entstehen eben nicht tausend Kopien jeder Methode.

Instanzfelder (Class Fields)

Instanzfelder kannst du direkt am Anfang des Klassenkörpers deklarieren, also außerhalb des constructor:

index.js
Output
Click Run to see the output here.

Felddeklarationen werden vor dem Constructor-Body ausgeführt – so, als stünden sie ganz am Anfang des constructor. Praktisch sind sie vor allem dann, wenn der Anfangswert nicht von Constructor-Argumenten abhängt. Das bleibt übersichtlicher, als den Constructor mit this.count = 0; this.step = 1; vollzupacken.

Hängen die Werte dagegen doch von Argumenten ab, gehört die Zuweisung in den Constructor – dort sind die Argumente schließlich im Scope.

Getter und Setter in JavaScript

Ein Getter oder Setter sieht aus wie eine Methode, verhält sich aber wie ein Property-Zugriff. Du liest oder schreibst den Wert ohne Klammern, und im Hintergrund läuft die Methode:

index.js
Output
Click Run to see the output here.

Beachte, wie das Ganze aufgerufen wird: t.fahrenheit (ohne Klammern) liest den Getter aus, t.fahrenheit = 100 löst den Setter aus. Von außen betrachtet sieht fahrenheit aus wie eine ganz normale Eigenschaft – tatsächlich wird der Wert aber bei jedem Zugriff neu aus celsius berechnet.

Getter sind ideal für abgeleitete Werte. Setter wiederum eignen sich gut, um einen Wert bei der Zuweisung zu validieren oder zu normalisieren. Übertreib es aber nicht damit: Wenn ein Getter aufwendig ist, wundern sich Leser deines Codes später, warum ein simpler "Property-Zugriff" plötzlich ordentlich Arbeit verrichtet.

Method Shorthand, Computed Names und this

Methoden in einer JavaScript-Klasse nutzen die Kurzschreibweise – kein function-Keyword, kein : zwischen Name und Rumpf:

index.js
Output
Click Run to see the output here.

Wenn add am Ende this zurückgibt, lässt sich Method Chaining umsetzen – jeder Aufruf gibt dieselbe Instanz zurück, sodass die nächste Methode direkt darauf weiterarbeiten kann.

Ein Stolperstein dabei: Methoden sind nicht automatisch an ihre Instanz gebunden. Sobald du eine Methode aus dem Objekt herauslöst und einzeln aufrufst, ist this weg:

index.js
Output
Click Run to see the output here.

Der Aufruf g.hello() funktioniert, weil der Punkt this automatisch mitliefert. Ein freistehender Aufruf fn() dagegen nicht. Wenn du eine losgelöste, vorgebundene Methode brauchst (typischer Fall bei Event-Handlern), binde sie entweder im Constructor oder nutze ein Arrow-Function-Klassenfeld: hello = () => \Hi, ${this.name}`;`.

Ein kleines lauffähiges Beispiel

Jetzt setzen wir die Bausteine zusammen — Instanzfelder, Constructor, Methoden und ein Getter:

index.js
Output
Click Run to see the output here.

Auf den ersten Blick verständlich: Die Klasse beschreibt genau, was ein BankAccount ist und was er können soll.

JavaScript Klassen sind eigentlich Funktionen

Eins solltest du dir merken: class ist im Grunde nur syntaktischer Zucker. Unter der Haube ist eine JavaScript Klasse nichts anderes als eine Funktion – genauer gesagt eine Constructor-Funktion – und ihre Methoden hängen an ClassName.prototype:

index.js
Output
Click Run to see the output here.

typeof User ergibt "function". greet hängt an User.prototype. Instanzen finden greet über die Prototype Chain – also genau den Mechanismus, den die Sprache seit ihren Anfängen kennt. Klassen liefern dir einfach eine saubere Syntax, um das Ganze aufzusetzen.

Dieses Mental Model zahlt sich später aus: Vererbung, instanceof und das Debuggen von Prototype Chains ergeben viel mehr Sinn, sobald du im Kopf hast, dass eine Klasse nichts anderes ist als eine Funktion mit Methoden an ihrem Prototype.

Als Nächstes: Vererbung

Bisher steht jede Klasse für sich allein. In realen Projekten arbeitest du aber meist mit Klassenhierarchien – ein Dog ist eine Art Animal, ein AdminUser eine Art User. Genau dafür gibt es die Keywords extends und super, und die schauen wir uns als Nächstes an.

Häufig gestellte Fragen

Wie legt man in JavaScript eine Klasse an?

Du schreibst das Keyword class, gefolgt vom Namen, und packst in den Block eine constructor-Methode sowie beliebige weitere Methoden. Eine Instanz erzeugst du dann mit new ClassName(...). Beispiel: class User { constructor(name) { this.name = name; } } — und anschließend new User('Ada').

Wofür ist der Konstruktor in einer JavaScript-Klasse da?

Der constructor läuft genau einmal, nämlich beim Aufruf von new ClassName(...). Seine Aufgabe ist es, die neue Instanz zu initialisieren — typischerweise werden die Argumente als Eigenschaften auf this gesetzt. Schreibst du keinen, bekommst du automatisch einen leeren Default-Konstruktor.

Was ist der Unterschied zwischen einer Klasse und einer Funktion in JavaScript?

Unter der Haube ist eine Klasse nichts anderes als eine Funktion — genauer gesagt eine Konstruktorfunktion, deren Methoden am Prototype hängen. Das class-Keyword ist also größtenteils syntaktischer Zucker, erzwingt aber den Aufruf mit new, macht extends sauber nutzbar und sorgt dafür, dass Methoden nicht enumerierbar sind. Für neuen Code solltest du daher immer class statt handgeschriebener Konstruktorfunktionen verwenden.

Lerne mit Coddy zu programmieren

LOS GEHT'S