Skip to content

Das Constructor Pattern in JavaScript – Ein ausführlicher Leitfaden

Published: at 07:00 AMSuggest Changes

Das Constructor Pattern in JavaScript – Ein umfassender Leitfaden

In der Welt von JavaScript haben sich unterschiedliche Wege etabliert, um neue Objekte zu erzeugen und zu strukturieren. Eines der wohl ältesten und zugleich bekanntesten Konzepte ist das sogenannte Constructor Pattern. Anders als beispielsweise das modulare Muster, bei dem man Closures nutzt, setzt das Constructor Pattern auf Funktionen, die mittels des Schlüsselworts new aufgerufen werden, um Objekte zu erstellen. Wer aus klassischen objektorientierten Sprachen wie Java oder C# kommt, wird mit diesem Ansatz ein vertrautes Gefühl haben, obwohl es in JavaScript letztlich immer noch um Prototypen im Hintergrund geht.

Das Constructor Pattern funktioniert dabei nach einem einfachen Prinzip: Man definiert eine Funktion, in der bestimmte Werte an this gebunden werden. Ruft man diese Funktion mit new auf, erhält man ein Objekt, das über eben diese Werte verfügt und zudem vom Prototypen der Konstruktorfunktion erbt. Dieser Mechanismus gilt als Herzstück des objektorientierten Ansatzes in JavaScript. Im Lauf der Zeit hat sich zwar die Syntax weiterentwickelt, insbesondere durch Klassen in ES6+, doch im Kern bleibt das Constructor Pattern eine der wichtigsten Grundlagen für das Erstellen wiederverwendbarer Objekte.


Was ist das Constructor Pattern?

Beim Constructor Pattern definierst Du eine Funktion, die als Konstruktor fungiert. Darin setzt Du Eigenschaften auf this, sodass jeder Aufruf mit new eine individuelle Instanz zurückgibt. Ein klassisches Beispiel:

function Car(brand, model) {
  this.brand = brand;
  this.model = model;

  this.startEngine = function() {
    console.log(`${this.brand} ${this.model} startet den Motor...`);
  };
}

// Erstellung zweier Instanzen
const tesla = new Car('Tesla', 'Model 3');
const bmw = new Car('BMW', 'i8');

tesla.startEngine();
// "Tesla Model 3 startet den Motor..."

Bei der Erstellung einer neuen Instanz mit new Car('Tesla', 'Model 3') passiert Folgendes:

  1. Ein leeres Objekt wird automatisch erzeugt.
  2. this wird auf dieses Objekt gebunden.
  3. Die Anweisungen im Konstruktor werden ausgeführt.
  4. Das erstellte Objekt erbt vom Prototypen der Funktion Car.
  5. Die Rückgabe des erstellten Objekts geschieht implizit.

Diese Mechanik nutzt man, um Objektinstanzen zu bilden, die jeweils eigene Zustände (Eigenschaften) besitzen, aber trotzdem dieselbe Grundlogik teilen.


Vor- und Nachteile des Constructor Patterns

Vorteile

Viele Entwickler:innen schätzen das Constructor Pattern, weil es eine klare, fast klassenähnliche Struktur bietet. Das new-Schlüsselwort wirkt vertraut für Teams, die aus Sprachen wie Java kommen. Mit Prototypen lassen sich Methoden optimal teilen, wodurch der Code leichtgewichtig bleibt. Ein Beispiel:

function Species(name, race) {
  this.name = name;
  this.race = race;
  
  this.aboutMe = function() {
    console.log(`Mein Name ist ${this.name} und ich bin ein ${this.race}.`);
  };
}

const luke = new Species('Luke', 'Mensch');
const chewbacca = new Species('Chewbacca', 'Wookie');

luke.aboutMe();
chewbacca.aboutMe();

Hier sieht man, dass jede Instanz eigene Daten (name, race) hat, aber alle Instanzen dieselbe Methode getInfo im Prototyp verwenden. Das reduziert Speicherverbrauch und fördert die Wiederverwendung von Code.

Nachteile

Auf der anderen Seite kann das Constructor Pattern für Einsteiger:innen verwirrend sein, da man das new zwingend benötigt. Vergisst man es, wird this falsch gebunden und man landet möglicherweise in fehlerhaftem Verhalten.

Zudem passiert es leicht, dass jemand Methoden direkt im Konstruktor selbst deklariert, wodurch jede Instanz eine Kopie dieser Methode erhält. Das ist zwar lauffähig, aber ineffizient. Die Nachteile liegen hier vor allem in:

function InefficientCar(brand) {
  this.brand = brand;

  // Für jede Instanz neue Funktion im Speicher
  this.drive = function() {
    console.log(`${this.brand} fährt!`);
  };
}

const myCar = new InefficientCar('Volvo');
const anotherCar = new InefficientCar('Audi');
// Beide haben eigene "drive"-Funktion, statt sie zu teilen.

Hier definiert man drive besser im Prototyp, sodass es einmalig vorliegt.

function Car(brand) {
  this.brand = brand;
}

// Für jede Instanz neue Funktion im Speicher
Car.prototype.drive = function() {
  console.log(`${this.brand} fährt!`);
};

const myCar = new Car('Volvo');
const anotherCar = new Car('Audi');
// Beide haben eigene "drive"-Funktion, statt sie zu teilen.

Hinzu kommt, dass die reine Konstruktor-Mechanik für sehr dynamische Muster oder partielles Clonen weniger flexibel ist als beispielsweise eine Factory-Funktion.


Kurzer Blick auf moderne ES6-Klassen

Seit ES6+ bietet JavaScript eine Klassen-Syntax, die das Constructor Pattern auf den ersten Blick kaschiert. Dennoch steckt unter der Haube dasselbe Prinzip: Prototypenvererbung. Nur die Schreibweise ändert sich. Ein Beispiel:

class Species {
  constructor(name, race) {
    this.name = name;
    this.race = race;
  }
  
  aboutMe() {
    console.log(`Mein Name ist ${this.name} und ich bin ein ${this.race}.`);
  };
}

const luke = new Species('Luke', 'Mensch');
const chewbacca = new Species('Chewbacca', 'Wookie');

luke.aboutMe();       // Mein Name ist Luke und ich bin ein Mensch.
chewbacca.aboutMe();  // Mein Name ist Chewbacca und ich bin ein Wookie.

Man erhält hier eine “leserlichere” und an klassische OOP-Sprachen angelehnte Syntax, was für viele Teams von Vorteil ist. Intern wird jedoch immer noch eine Konstruktorfunktion erzeugt, deren Prototyp alle Methoden enthält. So bleibt das altbekannte System erhalten, nur “komfortabler” verpackt.


Fazit

Das Constructor Pattern ist ein zentrales Puzzlestück für objektorientierte Kodierung in JavaScript. Es erleichtert das Erzeugen mehrerer Instanzen, die gemeinsame Methoden teilen. Entwickler:innen aus klassenbasierten Sprachen schätzen das vertraute Gefühl, das durch Konstruktorfunktionen und das Schlüsselwort new entsteht. Allerdings hat das Muster auch seine Tücken: Vergisst man new, riskiert man Fehlverhalten und wer Methoden direkt im Konstruktor deklariert, verplempert Code und Speicher. Durch das Auslagern von Funktionen in den Prototyp und den bewussten Umgang mit new kann man in den meisten Projekten jedoch eine saubere, klassenähnliche Struktur schaffen. ES6-Klassen erweitern diese Idee, indem sie das Constructor Pattern mit einer moderneren, kompakteren Schreibweise versehen und insbesondere Entwickler:innen aus objektorientierten Welten den Einstieg erleichtern.


FAQ – 10 häufig gestellte Fragen zum Constructor Pattern in JavaScript

1. Ist das Constructor Pattern für große Projekte geeignet?
Definitiv, solange Du die Methoden in den Prototyp auslagerst und auf eine konsistente Struktur achtest. Auch ES6-Klassen bieten sich an, da sie intern dasselbe Konstruktionsprinzip nutzen.

function BigClass(name) {
  this.name = name;
}
BigClass.prototype.doStuff = function() { /* ... */ };

2. Warum muss ich „new“ verwenden?
Ohne new würde this auf ein anderes Objekt zeigen (im Strict Mode wirfst Du sogar einen Fehler). Nur mit new erzwingst Du, dass JavaScript ein neues Objekt erstellt und den Konstruktor darauf anzuwenden.

3. Gibt es eine Warnung, wenn ich „new“ vergesse?
Nicht automatisch. Eine automatische Fehlerwarnung gibt es hier nur im Strict mode. Einige Linter wie z.B. ESLint melden ein solches Fehlverhalten.

4. Soll ich Methoden lieber direkt im Konstruktor oder im Prototyp definieren?
Fast immer im Prototyp. Wenn Du sie direkt im Konstruktor definierst, kopierst Du sie in jede Instanz. Das erhöht den Speicherbedarf. Im Prototyp hingegen wird die Methode nur einmalig angelegt:

Car.prototype.drive = function() { /* ... */ };

5. Was passiert, wenn ich den Konstruktor falsch schreibe?
Wenn Du z.B. function car() statt function Car() schreibst, verletzt Du keine Sprachregel, aber das Konventionsprinzip. Entwickler:innen erkennen Konstuktoren in JS am Großbuchstaben. Das ist eine gängige Stilfrage.

6. Wie erbt man mit dem Constructor Pattern?
Dazu ruft man zuerst Parent.call(this, ...) im Child-Konstruktor auf, um Eigenschaften zu initialisieren, und leitet den Prototyp ab:

Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;

Das bildet eine Prototypenkette, in der Child von Parent erbt.

7. Ist das Constructor Pattern und das „klassische OOP“ in JavaScript wirklich gleichwertig?
Nicht ganz. JavaScript bleibt eine prototypische Sprache. Das Constructor Pattern schafft aber ein klassenähnliches Gefühl. Echte Klassenhierarchien wie in C# oder Java gibt es nicht, auch wenn ES6-Klassen näher dran wirken.

8. Kann ich das Constructor Pattern in Kombination mit Modulen nutzen?
Ja, Du exportierst einfach Deine Konstruktorfunktionen bzw. ES6-Klassen aus einem Modul. In einem anderen Modul kannst Du sie dann importieren und per new Instanzen erzeugen.

// car.js
export function Car(brand, model) {
  this.brand = brand;
  this.model = model;
}

// main.js
import { Car } from './car.js';
const myCar = new Car('Toyota', 'Prius');

9. Wie teste ich Code, der auf dem Constructor Pattern basiert?
Du kannst wie bei jeder Funktion Mocks oder Spies nutzen, um Konstruktoraufrufe oder Prototypmethoden zu überprüfen. Wichtig ist, dass Du klare Trennung hast zwischen dem Erstellen einer Instanz und deren Methoden.

test('Konstruktor erstellt Objekt', () => {
  const c = new Car('Renault', 'Clio');
  expect(c.brand).toBe('Renault');
});

10. Soll ich lieber ES6-Klassen anstelle von Konstruktorfunktionen nutzen?
Das ist Geschmackssache und Teamkonvention. ES6-Klassen sind lesbarer für viele OOP-affine Entwickler:innen. Im Kern macht JavaScript dasselbe: Es konstruiert Objekte, die von CarClass.prototype erben. Du kannst also frei wählen, was Deinem Code mehr Klarheit gibt:

class CarClass {
  constructor(brand, model) {
    this.brand = brand;
    this.model = model;
  }
}

Damit bist Du gerüstet, das Constructor Pattern in JavaScript optimal zu nutzen. Ob Du Dich für die klassische Konstruktorfunktion entscheidest oder für die moderne ES6-Syntax, hängt von Deinen Teampräferenzen und Codevorgaben ab. Wichtig ist, dass Du das Prinzip dahinter verstehst und weißt, warum JavaScript trotz klassenähnlicher Syntax weiterhin eine prototypbasierte Sprache ist.


Buy me a coffee

Wenn Dir meine Beiträge gefallen und sie Dir bei Deiner Arbeit helfen, würde ich mich über einen “Kaffee” und ein paar nette Worte von Dir freuen.

Buy me a coffee



Previous Post
Das Strategie Pattern in JavaScript – Ein ausführlicher Leitfaden
Next Post
Das Prototype Pattern in JavaScript – Ein ausführlicher Leitfaden