this
in Funktionen: Warum der Aufruf alles entscheidet
Das Verhalten von this
in Funktionen ist eines der häufigsten Stolpersteine für JavaScript-Entwickler:innen. Anders als in vielen objektorientierten Programmiersprachen, bei denen this
stets auf das aktuelle Objekt verweist, ist this
in JavaScript dynamisch gebunden. Das bedeutet, der Kontext und damit der Wert von this
, wird erst zur Laufzeit anhand des Aufrufs bestimmt, nicht aufgrund der Stelle, an der die Funktion definiert wurde.
Dieses Verhalten kann sehr mächtig sein, aber auch zu viel Verwirrung führen, wenn man es nicht durchschaut. Deshalb schauen wir uns jetzt genau an, wie this
in normalen Funktionen, in Arrow Functions, im Strict Mode und mit Methoden wie call
, apply
und bind
funktioniert.
Normale Funktionen: this
hängt vom Aufruf ab
Wenn eine Funktion nicht als Methode eines Objekts aufgerufen wird, sondern „einfach so“, dann ist der Wert von this
im nicht-strikten Modus das globale Objekt (window
im Browser, global
in Node.js). Im Strict Mode ist this
dagegen undefined
.
function showThis() {
console.log(this);
}
showThis(); // Im Browser: window
Mit aktiviertem Strict Mode:
"use strict";
function showThisStrict() {
console.log(this);
}
showThisStrict(); // undefined
Dieser Unterschied ist entscheidend, da er beeinflusst, ob this
gültig ist, oder ob es zu einem Laufzeitfehler kommt, wenn man auf eine Eigenschaft zugreift.
Funktionen in Objekten: Methoden und ihre Tücken
Wird eine Funktion als Methode eines Objekts aufgerufen, zeigt this
auf genau dieses Objekt. Das Verhalten ist dann intuitiv, aber nur, wenn die Funktion direkt über das Objekt aufgerufen wird.
const user = {
name: "Lea",
greet() {
console.log(`Hallo, ich bin ${this.name}`);
}
};
user.greet(); // "Hallo, ich bin Lea"
Problematisch wird es, wenn die Methode „ausgelagert“ und außerhalb des Objekts verwendet wird:
const greetFn = user.greet;
greetFn(); // undefined oder Fehler – `this` zeigt nicht mehr auf `user`
Hier verliert die Funktion den Bezug zum ursprünglichen Objekt. Um das zu verhindern, kann man sie binden:
const boundGreet = user.greet.bind(user);
boundGreet(); // "Hallo, ich bin Lea"
Arrow Functions: this
ist hier lexikalisch
Arrow Functions verhalten sich anders. Sie binden kein eigenes this
, sondern übernehmen es vom umgebenden (lexikalischen) Kontext. Das ist besonders nützlich, wenn man in einem Funktionskörper auf das umgebende Objekt verweisen möchte, zum Beispiel in Callbacks oder Event-Handlern.
const person = {
name: "Timo",
introduce() {
setTimeout(() => {
console.log(`Ich heiße ${this.name}`);
}, 1000);
}
};
person.introduce(); // "Ich heiße Timo"
Die selbe Funktion müsste, wenn man sie ohne Arrow Function, mit einer “normalen” Funktion schreiben würde, den Kunstkniff “that = this” nutzen, um den umgebenden Scope mit in die Funktion zu transferieren.
const person = {
name: "Timo",
introduce() {
const that = this;
setTimeout(function() {
console.log(`Ich heiße ${that.name}`);
}, 1000);
}
};
person.introduce(); // "Ich heiße Timo"
Wäre setTimeout
mit einer normalen Funktion geschrieben, wäre this.name
undefined
, da this
im Timeout-Kontext nicht mehr auf person
zeigt. Hier wird das korrigiert, indem der this
Kontext in die Konstante that
übertragen wird und in der ausführenden Funktion dann mit that
anstelle gearbeitet wird.
Strict Mode: Besseres this
-Verhalten
Seit ES5 gibt es den Strict Mode, der viele unsichere Konstrukte in JavaScript entschärft. Einer der größten Vorteile ist, dass this
in Funktionen, die ohne Objektbezug aufgerufen werden, nicht mehr automatisch auf das globale Objekt zeigt.
"use strict";
function sayHello() {
console.log(this); // undefined statt window
}
Das schützt vor versehentlichen Zugriffen auf das globale Objekt und zwingt Entwickler:innen dazu, bewusster mit dem Kontext umzugehen.
Kontext erzwingen mit bind
, call
und apply
Wenn man den Kontext explizit setzen möchte, kann man das mit den Methoden bind
, call
und apply
tun:
bind()
gibt eine neue Funktion zurück, derenthis
dauerhaft auf ein bestimmtes Objekt gesetzt ist.call()
ruft die Funktion direkt auf, mit einem bestimmtenthis
.apply()
funktioniert wiecall()
, erwartet aber die Argumente als Array.
function printAge(years) {
console.log(`${this.name} ist ${years} Jahre alt`);
}
const user = { name: "Jonas" };
printAge.call(user, 28); // Jonas ist 28 Jahre alt
printAge.apply(user, [30]); // Jonas ist 30 Jahre alt
const boundPrint = printAge.bind(user);
boundPrint(35); // Jonas ist 35 Jahre alt
Diese Methoden sind vor allem bei Event-Handlern oder dynamisch erzeugten Funktionen sehr hilfreich, um einen stabilen Kontext zu behalten.
Fazit: Funktionen und this
– alles eine Frage des Kontexts
In JavaScript ist der Funktionsaufruf entscheidend dafür, was this
gerade ist. Während viele Sprachen this
statisch an das Objekt binden, denkt JavaScript eher in Aufrufen als in Definitionen. Wer das versteht, kann mit this
sehr flexible und wiederverwendbare Funktionen schreiben und gleichzeitig klassische Fehler vermeiden.
Die wichtigste Regel lautet: Nicht merken, wo this
definiert wurde, sondern merken, wie es aufgerufen wurde.
Mit dem zusätzlichen Wissen über Arrow Functions, Strict Mode und bind
/call
/apply
hast du jetzt ein komplettes Toolset zur Verfügung, um this
in Funktionen sicher zu verwenden.
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.