Javascript this – das Objekt, das mich rief

this ist ein Verweis auf das Objekt, das die aktuelle Javascript-Funktion aufgerufen hat. this ist ein Segen für die Flexiblität und ein sprudelnder Quell für Trugschlüsse. Jede Javascript-Funktion hat ein verborgenes Argument namens this.

Javascript this: die Referenz auf das Objekt, das gerade verarbeitet wird

Objekte, die sich selber untersuchen

Bei jedem Aufruf der Funktion wird dieses Argument - sozusagen hinter den Kulissen - zusammen mit einem Zeiger auf das Objekt, das die Funktion aufrief, übergeben. this hat eine ähnliche Funktion wie das »sie« in diesem Satz: »Martina stand früh auf, denn sie wollte Kurts Ankunft nicht verpassen«. Durch »sie« ist klar, dass die zuerst erwähnte Martina gemeint ist.

In objektorientierten Sprachen brauchen wir etwas, um auf das aktuelle Objekt zuzugreifen, das gerade vom Script behandelt wird. Dank Javascript this können sich Objekte selbst untersuchen und Auskunft über ihre Eigenschaften geben.

this is a moving target / this ist ein bewegliches Ziel

this hat keinen Wert, bis ein Objekt die Funktion aufruft, in der this definiert ist.

Javascript this gibt es in jedem Funktions- oder globalen Umfeld. Aber in jedem Umfeld hat this eine andere Zuordnung – ist an ein anderes Element gebunden.

this-Aufruf binding
Beispiele für this – für ein div-Element, input und eine Funktion, die auf mehreren Elementen aufgerufen werden kann.

Der Wert von this innerhalb einer Funktion hängt von dem Objekt ab, das die Funktion aufgerufen hat. Im Bild oben ist this in function b einmal das div-Element, auf dem die Funktion aufgerufen wurde, und ein anderes this, wenn die Funktion b auf dem form-Element aufgerufen wurde. Für Einsteiger immer wieder ein Mysterium …

Javascript ist eine spätbindende (late binding) Programmiersprache. Verglichen mit anderen Programmiersprache bindet Javascript sein this sogar außerordentlich spät. this wird nicht während der Compilierung gebunden, auch nicht zur Laufzeit wie in anderen Programmiersprachen, sondern zum Zeitpunkt des Aufrufs. Das verstört selbst erfahrene Programmierer, die von objektorientierten Programmiersprachen kommen.

Einordnung von this

Der Wert von this ist abhängig von Strict Mode, Methodenaufruf, Event Handler oder Arrow Function.

Entscheidungsgraph für this
Diagramm zur Einordnung von this

Das sind die typischen Fälle:

Global / im Strict Mode
Im Browser → window oder undefined (strict).
In einer Methode
obj.method() → this zeigt auf obj.
Als normale Funktion
func() → this = global (oder undefined im strict mode).
Im Event-Handler
element.onclick = function() { console.log(this) } → zeigt auf das DOM-Element.
In Arrow Functions
Besonderheit: this wird lexikalisch übernommen (kein eigenes this).

this bei events auf HTML-Elementen

Das mag kein Beispiel für gutes Javascript sein, denn das ist altmodisches inline-Javascript. Aber nichts könnte Javascript this besser in Szene setzen:

<div onmouseover="this.innerHTML='Ich bin jetzt this!'"></div>

Wenn die Maus über das HTML div hovert, soll dieses div den Text Ich bin jetzt this zeigen.

Javascript this bei Funktionen

Und einen Schritt weiter: das Javascript this in einer Funktion

<div>
	<button id="but">Klick!</button>
</div>
…
<script>
if (document.getElementById('but')) {
	const button = document.getElementById('but');
	button.onclick = function() {
		this.innerHTML = "ICH BIN THIS!";
	}
}
</script>

In diesem Fall ist der Eigentümer oder Aufrufer der Funktion this.

Was ist dieses this?

this ist ein bewegliches Ziel. Ein paar handfeste Regeln:

  1. Außerhalb von allen Funktionen verweist this auf das globale Objekt. In einem Browser ist das traditionell das Window-Objekt.

    console.log ("this.location " + this.location);
    

    gibt die URL der aktuelle Seite aus – ein Element des Window-Objekts.

  2. In einem Event Handler (z.B. einem onclick) verweist this auf das DOM-Element, auf dem das Ereignis ausgelöst wurde.

    document.getElementById ('foo').onclick = function () {
        alert (this.nodeName);
    }
    
  3. Wenn eine Funktion als Constructor aufgerufen wird, wird ein neues Objekt erzeugt und this an das Objekt gebunden.

    function Foo () {
        this.bar = 1;
    }
    new Foo().bar;
    
  4. Wenn Javascript im Strict-Mode läuft, darf this nicht auf das globale Object (also Window in Browsern) verweisen. Wenn also eine Funktion nicht als Methode eines Objekts aufgerufen wird oder this nicht manuell durch call oder apply an ein Element gebunden wurde, liefert this undefined.

    function loo () {
        return this;
    }
    console.log (loo()); // gibt aus: loo *** undefined
    

this im strict mode

In globalen Funktionen ist this im strict mode also undefined, nicht aber in Constructor-Funktionen.

let person = {
   vorname: "Penelope",
   nachname: "Barrymore",
   vollname: function () {​
      console.log(this.vorname + " " + this.nachname);
      // Hätte auch so geschrieben werden können:​​
      console.log(person.vorname + " " + person.nachname);
   }
}

Würden person.vornamen und person.nachname in der Constructor-Funktion anstelle von this.vorname und this.nachname benutzt, wären die Anweisungen u.U. nicht mehr eindeutig – z.B. wenn eine weitere globale Variable person (von der wir vielleicht nichts wissen) existiert. Derartige Fehler sind nicht einfach aufzufinden, darum wird hier this bevorzugt.

this mit bind neu definieren

call, apply und bind steuern und kontrollieren das Verhalten von this von Funktionen. Jede Funktion hat Zugriff auf .apply(), .bind() und .call(). Diese drei werden auch als »context manipulation methods« bezeichnet, also Methoden zur Kontextsteuerung. Sie steuern den this-Wert von Funktionen und erlauben das Festlegen von Argumenten.

function.bind ()

function.bind() führt die Funktion nicht aus, sondern gibt eine Funktion zurück, die später ausgeführt werden kann – z.B., wenn später ein Event eintritt. So bleibt der Kontext in asynchronen Callbacks und Events erhalten.




			

bind() ist eine elegante Methode, um einen oder mehrere Parameter an eine Callback-Funktion zu übergeben, ohne dass die Funktion sofort aufgerufen wird. Ein Beispiel für die Anwendung von bind() ist ein addEventListener, der eine EventHandler-Funktion für eine Gruppe von Elementen ausführt, um ein vertikales Akkordeon zu animieren.

<div class="demo">
	<div class="box box1 boxAni"></div>
	<div class="box box2"></div>
	<div class="box box3"></div>
	<div class="box box4"></div>
</div>
const boxen = document.querySelectorAll(".box");

const handleStackMove = function(elem) {
	console.log (this.message)
	document.querySelector(".boxAni").classList.remove("boxAni");
	elem.classList.add("boxAni");
}

const context = {
	message : "Das ist mein Akkordeon"
}

boxen.forEach ((item) => {
	item.addEventListener ("click", 
		handleStackMove.bind(context, item)
	)
});
bind() erspart die anonyme Funktion, die wiederum eine Callback-Funktion aufruft, in der Parameter übergeben werden können. bind() bindet das Event mit einer Funktion, die mit dem Schlüsselwort this (erster Parameter) auf das Objekt context verweist. Der zweite Parameter ist das geklickte Element im Akkordeon.

Neben dem einfachen Binden von Funktionen im EventListener sorgt bind() dafür, dass der Wert von this bei asynchronen Aufrufen nicht verloren geht.

function.call

.bind(), wenn eine Funktion später in einem bestimmten Kontext aufgerufen werden soll (z.B. bei Events),
.call() / .apply(), wenn eine Funktion sofort aufgerufen werden soll und den Kontext ändert.

Das einfach Objekt satz1 hat keine Methoden, die Methode mwst hat keine Eigenschaft num, gibt aber this.num zurück.

let satz1 = { num:19 };

let mwst = function (a) {
   return this.num * a / 100; 
}

mwst.call( satz1, 100);

Das Ergebnis des Aufrufs mwst.call( satz1, 100) ist 19. Die Funktion könnte genauso für ein zweites Objekt satz2 = { num:11 } aufgerufen werden.

19

Wenn die Funktion mehrere Parameter hat, werden sie allesamt im call-Aufruf aufgeführt.

let obj = { num: 2 };
let sum = function (a, b, c) {
   return this.num + a + b + c; 
}

sum.call( obj, 4, 6, 8);

Das Ergebnis wäre wie erwartet

20

Ein call-Aufruf mit einem Objekt, das mehrere Elemente hat:

let obj = { a: 2, b: 8 };
let sum = function (c) {
   console.log (this.a + this.b + c);
}

sum.call ( obj, 3);
13

function.apply

Anstelle der drei Parameter könnte ein Array übergeben werden, dann wäre der Aufruf apply anstelle von call.

let obj = { num:2 };
let arr = [3, 5, 9];
let add = function (a, b, c) {
   //console.log ("apply " + this.num + a + b + c);
}
add.apply( obj, arr);

call, apply, bind – welche Methode für welchen Fall?

Fall Lösung
Sofort aufrufen, this ändern call() oder apply()
Sofort aufrufen, Argumente als Array apply()
Funktion später mit festem this nutzen bind()
this in Event-Handlern beibehalten bind()

Mit dem Spread-Operator (...) kann apply() oft durch call() ersetzt werden:

Math.max.call(null, ...numbers); // Statt apply()

apply() wird dadurch im modernen Scripts seltener verwendet.

const myFlowers = {
   name : "Hortensie",
   getName : function () {
      return console.log (this.name);
   }
};
myFlowers.getName();
const myFlowers = {
   name : "Hortensie",
   getName : function () {
      return console.log (this.name);
   }
};
const moreFlowers = myFlowers.getName.bind ({"Nelke"});
moreFlowers ();
Suchen auf mediaevent.de