mitmario.dev

Methoden und this

JavaScript Im Browser 3 Min Lesezeit 4 BeispieleLektion 3 von 9

Eine Methode ist nichts Neues: es ist eine Funktion, die als Eigenschaft eines Objekts steht. Neu ist nur, dass sie an die anderen Eigenschaften herankommt, und das Wort dafür ist this. Lektion 5.4 hat die Frage ausdrücklich hierher vertagt, weil sie ohne Objekt nicht zu zeigen ist.

Eine Funktion mit Doppelpunkt davor

Eine Funktion als Eigenschaft
const kurs = {
  titel: "JavaScript",
  stunden: 47,

  // Die Kurzschreibweise: Name, Klammern, geschweifte Klammern.
  // Kein function, kein Doppelpunkt.
  info() {
    return `${this.titel} dauert ${this.stunden} Stunden`;
  },

  // Eine Methode darf eine andere aufrufen, auch über this.
  kurzfassung() {
    return this.info().toUpperCase();
  },
};

console.log(kurs.info());
console.log(kurs.kurzfassung());

// Ausgeschrieben ginge es auch, es ist nur länger.
const alt = {
  titel: "CSS",
  info: function () {
    return this.titel;
  },
};
console.log(alt.info());

Du kannst eine Funktion überall hinschreiben, wo ein Wert erwartet wird, und in einem Objekt ist das die rechte Seite eines Doppelpunkts. Weil das so häufig vorkommt, gibt es dafür eine Kurzschreibweise: Name, runde Klammern, geschweifte Klammern. Kein function, kein Doppelpunkt.

Innerhalb der Methode kommst du mit this an das Objekt heran, zu dem sie gehört. this.titel liest also dieselbe Eigenschaft, die von außen kurs.titel heißt.

Eine Methode darf über this auch eine andere Methode aufrufen. Das ist der übliche Weg, eine große Ausgabe aus kleinen Bausteinen zu bauen, und es ist genau der Gedanke aus Lektion 5.8: kleine Funktionen, die sich gegenseitig benutzen.

Woran this wirklich hängt

this zeigt auf das, was links vom Punkt steht
function wasBinIch() {
  return this;
}

// Dieselbe Funktion, zwei Objekten zugewiesen.
const a = { kennung: "A", frag: wasBinIch };
const b = { kennung: "B", frag: wasBinIch };

console.log("a.frag():", a.frag().kennung);
console.log("b.frag():", b.frag().kennung);

// Und ohne Punkt davor: this ist dann nicht das Objekt.
const losgeloest = a.frag;
console.log("Ohne Objekt:", losgeloest().kennung);

// Der klassische Fall dahinter: eine Methode wird weitergereicht
// und verliert dabei ihr this.
const kurs = {
  titel: "JavaScript",
  zeigen() {
    return this.titel;
  },
};
const zeigen = kurs.zeigen;
console.log("Weitergereicht:", zeigen());

Hier kommt der Satz, um den es in dieser Lektion geht.

this hängt am Aufruf, nicht an der Stelle, an der die Funktion steht. Es zeigt auf das, was beim Aufruf links vom Punkt stand. Dieselbe Funktion, zwei Objekten zugewiesen, liefert deshalb zwei verschiedene Ergebnisse: a.frag() bekommt a, b.frag() bekommt b.

Daraus folgt der Fall, der Anfänger am häufigsten trifft. Löst du eine Methode aus ihrem Objekt heraus und rufst sie ohne Punkt auf, ist links vom Punkt nichts mehr, und this zeigt nicht mehr auf das Objekt. Die Methode liefert dann undefined statt des erwarteten Werts, ohne dass irgendwo ein Fehler steht.

Worauf es stattdessen zeigt, kannst du dir ansehen, und das ist die Zeile, die den ganzen Absatz greifbar macht. Tipp a.frag() in die Eingabezeile der Console: Zurück kommt {kennung: "A", frag: ƒ wasBinIch()}, also das Objekt selbst. Tipp jetzt losgeloest(), und zurück kommt Window {…}, das Fenster des Browsers. Deshalb ist .kennung danach undefined: Das Fenster hat keine solche Eigenschaft, und niemand hat sich beschwert.

Das passiert selten absichtlich und oft nebenbei. Sobald du eine Methode irgendwohin weiterreichst, ist sie herausgelöst. In Abschnitt 12 ist das der Grund, warum ein Klick-Handler plötzlich nichts mehr findet, und dort steht auch der Ausweg.

Warum eine Arrow Function hier nicht geht

Die Arrow Function als Methode
const kurs = {
  titel: "JavaScript",

  // Gewöhnliche Funktion: this ist das Objekt.
  richtig() {
    return this.titel;
  },

  // Arrow Function: this kommt von außen und ist hier nicht
  // das Objekt. Kein Fehler, nur undefined.
  falsch: () => this.titel,
};

console.log("richtig():", kurs.richtig());
console.log("falsch():", kurs.falsch());

// Wichtig: das liegt nicht an der Kürze der Schreibweise.
// Diese hier ist genauso kurz und funktioniert.
const kurz = {
  titel: "CSS",
  zeigen() {
    return this.titel;
  },
};
console.log("kurz.zeigen():", kurz.zeigen());

Eine Arrow Function hat kein eigenes this. Sie nimmt das von der Stelle, an der sie geschrieben steht. Steht sie in einem Objektliteral auf oberster Ebene, ist das nicht das Objekt, denn ein Objektliteral ist kein Gültigkeitsbereich. Sie bekommt das this von außerhalb, und dort steht nichts Brauchbares.

Das Ergebnis ist kein Fehler, sondern undefined, und deshalb ist der Fall so unangenehm. Der Code sieht richtig aus, läuft durch und liefert Unsinn.

Ein Missverständnis dazu räumt das Beispiel gleich mit ab: Es liegt nicht an der kurzen Schreibweise. Die Methoden-Kurzschreibweise ist genauso kurz und funktioniert einwandfrei. Es liegt allein daran, woher die Arrow Function ihr this nimmt.

Die Regel, die du dir merken kannst

Arrow Function als Callback in einer Methode
const kurs = {
  titel: "JavaScript",
  themen: ["Objekte", "Arrays", "Events"],

  // Die Methode ist eine gewöhnliche Funktion, damit this stimmt.
  // Der Callback darin ist eine Arrow Function, damit dasselbe
  // this weiter gilt.
  liste() {
    return this.themen.map((thema) => `${this.titel}: ${thema}`);
  },

  // Mit einer gewöhnlichen Funktion als Callback geht das schief.
  listeKaputt() {
    return this.themen.map(function (thema) {
      return `${this.titel}: ${thema}`;
    });
  },
};

console.log(kurs.liste());
console.log(kurs.listeKaputt());

Gewöhnliche Funktion als Methode, Arrow Function als Callback. Damit liegst du fast immer richtig, und das letzte Beispiel zeigt, warum beides zusammengehört.

Die Methode liste ist eine gewöhnliche Funktion, also stimmt ihr this. Der Callback darin ist eine Arrow Function, und weil die kein eigenes this mitbringt, gilt darin weiterhin dasselbe this. Beide Zugriffe finden das Objekt.

Bei listeKaputt ist der Callback eine gewöhnliche Funktion. Die bringt ihr eigenes this mit, und weil map sie ohne Objekt aufruft, ist das nicht der Kurs. Genau dieses Verhalten war der Grund, aus dem die Arrow Function 2015 überhaupt eingeführt wurde.

Was in dieser Lektion falsch ist, ist in Abschnitt 12 also richtig, und umgekehrt. Der Unterschied ist nicht die Schreibweise, sondern die Frage, ob die Funktion ihr eigenes this haben soll oder nicht.

Zum Mitnehmen

this hängt am Aufruf, nicht an der Stelle, wo die Funktion steht. Es zeigt auf das, was links vom Punkt steht, und sonst auf nichts Brauchbares.

Jetzt du

Basis Konto, kostenlos

Zu dieser Lektion gehört eine Aufgabe. Du schreibst den Code selbst, und nach jedem Lauf sagt dir eine Prüfliste, was schon stimmt.

Dafür brauchst du das Basis Konto. Es kostet nichts, und ein Passwort gibt es auch nicht.

Was in dieser Lektion steckt

  • Artikel mit 4 Beispielen zum Ausprobieren

    Steht hier, ohne Konto lesbar.

  • Aufgabe im Editor, direkt im Browser geprüft

    Öffnet sich mit dem Basis Konto.