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
thisin 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
thisschwer 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:
- Wird die Funktion mit
newaufgerufen? Dann istthisdie neue Instanz. - Gibt es
call,applyoderbind? Dann istthisexplizit festgelegt. - Steht vor dem Aufruf ein Objekt? Dann ist
thisdieses Objekt. - Ist es eine Arrow Function? Dann kommt
thisaus dem äußeren Kontext. - 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: