blog / das-this-keyword-verstehen

Das this-Keyword verstehen: Eine klare mentale Karte

Einleitung: this ist kein Zauber, sondern Kontext

Wenn ich eine Liste der häufigsten Fragen aus Code-Reviews und Pair-Programming-Sessions erstellen würde, wäre this ganz oben dabei. Nicht, weil es besonders kompliziert wäre, sondern weil JavaScript hier eine Regel hat, die sich nur schwer “mit Bauchgefühl” erraten lässt: this hängt vom Aufruf ab, nicht von der Definition. Wer das einmal wirklich verinnerlicht, spart sich Stunden an Debugging und verwirrenden undefined-Fehlern.

In diesem Beitrag bekommst du eine klare mentale Karte für this, inklusive typischer Fallen und Best Practices. Wir gehen von der Grundregel über die vier Bindungsarten bis hin zu Arrow Functions, Events und Modulen. Am Ende weißt du in jeder Situation, was this bedeutet.

Die goldene Regel: this wird beim Aufruf entschieden

In JavaScript ist this kein festes Attribut einer Funktion. Eine Funktion kann in vielen Kontexten aufgerufen werden, und der Call-Site bestimmt den Wert von this. Das ist der Kern. Wenn du dir nur einen Satz merken willst, dann diesen.

Ein simples Beispiel zeigt die Idee:

function hello() {
  console.log(this);
}

hello(); // Was ist this?

Die Antwort hängt von der Umgebung und vom Modus ab. Im Browser (ohne Strict Mode) ist es window. Im Strict Mode ist es undefined. Diese Unterschiede wirken klein, sind aber der Grund, warum this so oft “kaputt” aussieht.

Die vier Bindungsregeln für this

Wenn du den Wert von this bestimmen willst, prüfe diese Regeln in der Reihenfolge. Die erste, die passt, gewinnt.

1) Default Binding (normaler Funktionsaufruf)

Ein normaler Funktionsaufruf ohne Objekt davor nutzt die Default-Regel.

function showThis() {
  console.log(this);
}

showThis(); // Browser: window (ohne strict), undefined (strict)

Warum wichtig? Weil du hier oft unbeabsichtigt landest. Ein this-Fehler ist meistens ein verlorener Kontext, der auf Default Binding zurückfällt.

2) Implicit Binding (Methodenaufruf)

Wenn du eine Funktion als Methode eines Objekts aufrufst, zeigt this auf dieses Objekt.

const user = {
  name: "Mia",
  greet() {
    console.log(`Hi, ich bin ${this.name}`);
  }
};

user.greet(); // Hi, ich bin Mia

Klingt simpel, aber jetzt die klassische Falle:

const greet = user.greet;
greet(); // this ist weg -> undefined oder window

Hier ist this nicht mehr user, weil die Funktion ohne Objekt davor aufgerufen wird. Das ist der Moment, in dem viele Entwickler denken, JavaScript sei “kaputt”. In Wahrheit ist nur der Kontext verloren gegangen.

3) Explicit Binding (call, apply, bind)

Mit call, apply und bind bestimmst du den Wert von this explizit.

function introduce(city) {
  console.log(`${this.name} aus ${city}`);
}

const person = { name: "Tom" };

introduce.call(person, "Hamburg");
introduce.apply(person, ["Berlin"]);

const introForTom = introduce.bind(person);
introForTom("Köln");

call und apply führen die Funktion sofort aus, bind erzeugt eine neue Funktion mit festem this. Ich nutze bind häufig, wenn ich eine Methode als Callback weitergebe.

4) new Binding (Konstruktoren)

Wenn du eine Funktion mit new aufrufst, wird ein neues Objekt erstellt und this zeigt darauf.

function User(name) {
  this.name = name;
}

const anna = new User("Anna");
console.log(anna.name); // Anna

new ist eine der höchsten Prioritäten. Selbst wenn du bind benutzt, kann new das überschreiben.

Arrow Functions: kein eigenes this

Arrow Functions haben kein eigenes this. Stattdessen übernehmen sie den Wert aus dem umgebenden Kontext (lexikalisches this). Das macht sie perfekt für Callbacks, in denen du den äußeren Kontext behalten willst.

const counter = {
  count: 0,
  start() {
    setInterval(() => {
      this.count += 1;
      console.log(this.count);
    }, 1000);
  }
};

counter.start();

Mit einer normalen Funktion wäre this in setInterval verloren. Die Arrow Function hält den Kontext fest.

Typische Falle: Callbacks verlieren this

Ein Klassiker aus der Praxis: du hast eine Klasse, und innerhalb eines Callbacks ist this plötzlich undefined.

class Timer {
  constructor() {
    this.seconds = 0;
  }

  start() {
    setTimeout(function () {
      this.seconds += 1; // this ist nicht die Instanz
    }, 1000);
  }
}

Lösung 1: Arrow Function.

start() {
  setTimeout(() => {
    this.seconds += 1;
  }, 1000);
}

Lösung 2: bind.

start() {
  setTimeout(function () {
    this.seconds += 1;
  }.bind(this), 1000);
}

Ich persönlich greife meistens zur Arrow Function, weil sie lesbarer ist und weniger kognitiven Overhead erzeugt.

this in DOM-Events

In klassischen Event-Handlern (mit addEventListener) zeigt this auf das Element, das das Event ausgelöst hat.

const button = document.querySelector("button");

button.addEventListener("click", function () {
  console.log(this); // <button>...</button>
});

Wenn du hier eine Arrow Function nutzt, übernimmt sie this aus dem äußeren Kontext (meist window oder undefined). Das ist oft nicht das, was du willst. In Event-Handlern nutze ich daher bewusst eine normale Funktion.

this in Node.js und Modulen

Im Browser ist das globale Objekt window. In Node.js ist es global. Aber: In modernen Modulen (type: module oder .mjs) ist this auf oberster Ebene undefined. In CommonJS ist this auf Modulebene oft module.exports. Das heißt: this kann je nach Runtime und Modulformat unterschiedlich sein. Ein weiteres Argument, this nicht für globale Logik zu missbrauchen.

Best Practices: So bleibt this beherrschbar

Ein paar Regeln, die mir in realen Projekten geholfen haben:

  • Vermeide this in Utility-Funktionen. Halte diese Funktionen möglichst “pure”.
  • Nutze Arrow Functions für Callbacks, die auf den äußeren Kontext zugreifen.
  • Wenn du Methoden weiterreichst, binde sie früh (z. B. im Konstruktor).
  • Halte deine Objekte klein und übersichtlich. Große Objekte mit vielen Methoden machen this schwer durchschaubar.
  • Verwende class-Syntax, wenn die Beziehung zwischen Instanz und Methoden klar sein soll.

Mentales Modell: Die 5-Sekunden-Checkliste

Wenn du bei einem Bug schnell herausfinden willst, was this ist, geh diese Fragen in genau dieser Reihenfolge durch. Ich mache das oft live im Kopf, während ich den Code lese:

  1. Wird die Funktion mit new aufgerufen? Dann ist this die neue Instanz.
  2. Gibt es call, apply oder bind? Dann ist this explizit festgelegt.
  3. Steht vor dem Aufruf ein Objekt? Dann ist this dieses Objekt.
  4. Ist es eine Arrow Function? Dann kommt this aus dem äußeren Kontext.
  5. Sonst: Default Binding (global oder undefined).

Ein kleines Beispiel, das diese Reihenfolge demonstriert:

const box = {
  value: 42,
  show() {
    console.log(this.value);
  }
};

const show = box.show;
show(); // Default Binding -> undefined oder window
show.call(box); // Explicit Binding -> 42

Wenn du diese Checkliste wirklich nutzt, verschwindet der “this ist manchmal komisch”-Effekt fast komplett.

this in Klassenfeldern und Prototypen

In Klassen landen Methoden standardmäßig auf dem Prototyp. Das ist speichereffizient, weil alle Instanzen die gleiche Funktion teilen. Arrow Functions als Klassenfelder landen dagegen direkt auf der Instanz. Das kann praktisch sein, weil der Kontext automatisch gebunden ist, kostet aber pro Instanz Speicher.

class Panel {
  constructor(title) {
    this.title = title;
  }

  // Prototyp-Methode
  showTitle() {
    console.log(this.title);
  }

  // Instanz-Methode mit gebundenem this
  showTitleArrow = () => {
    console.log(this.title);
  };
}

Beides ist legitim. Ich nutze Prototyp-Methoden für die meisten Fälle und Arrow-Methoden nur dann, wenn ich sie als Callback weiterreichen muss.

Warum this in modernen Frameworks seltener ist

In React-Funktionskomponenten taucht this gar nicht mehr auf. Stattdessen nutzt du Hooks, die ohne Kontext arbeiten. In Vue (Options API) ist this dagegen sehr präsent, weil data, methods und computed gemeinsam auf einer Instanz hängen. Mit der Composition API verschiebt sich das wieder in Richtung expliziter Importe und Funktionen. Das zeigt: Je funktionaler der Code-Stil, desto weniger brauchst du this. Das ist kein Dogma, aber eine gute Orientierung, wenn du neue Code-Strukturen designst.

Typische Fehler aus der Praxis

Ein häufiger Bug entsteht, wenn du Methoden per Destructuring herausziehst: const { save } = user; save(); wirkt harmlos, verliert aber den Kontext. In Reviews sehe ich auch oft this in reinen Utility-Modulen, obwohl dort eigentlich keine Instanz existiert. Ein weiteres klassisches Problem: Callback-Registrierung mit addEventListener und this-Logik, aber die Funktion wird später wiederverwendet und verliert den ursprünglichen Aufrufkontext. Mein Gegenmittel ist simpel: Wenn eine Funktion this braucht, dann sorge explizit für eine klare Call-Site (z. B. obj.method()), oder binde sie sofort. Und wenn eine Funktion kein this braucht, dann mach das bewusst sichtbar, indem du sie als reine Funktion definierst. Das reduziert Fehlerquellen drastisch.

Verbindung zum Tutorial

Wenn du this Schritt für Schritt und mit Übungen lernen willst, ist das passende Tutorial der nächste logische Schritt: JavaScript Strict Mode & this-Keyword. Dort bauen wir die Regeln praktisch auf, inkl. kleiner Tests.

Fazit

this ist nicht magisch, sondern eine Frage des Aufrufs. Wenn du die vier Bindungsregeln kennst und weißt, wann Arrow Functions ihren lexikalischen Kontext übernehmen, kannst du this in jeder Situation zuverlässig vorhersagen. Genau das ist der Unterschied zwischen “Trial and Error” und einem soliden mentalen Modell.

Am Ende zählt nicht, dass du jede Ausnahme kennst, sondern dass du eine klare Regelkette im Kopf hast. Dann ist this keine Stolperfalle mehr, sondern ein Werkzeug.


Weiterführende Ressourcen: