Kein bind für Lambda-Ausdrücke

the next big thing  –  1 Kommentare

Wer regelmäßig in JavaScript entwickelt, weiß um die Tücken des this-Schlüsselworts. Vor allem jenen Entwicklern, die primär über Erfahrung mit Sprachen wie C# oder Java verfügen, fällt das Verständnis von this schwer. Lambda-Ausdrücke schaffen Abhilfe – meistens.

Eigentlich lässt sich das Verhalten von this in JavaScript mit einem einzigen Satz hinreichend erklären: Der Wert von this wird nicht dadurch bestimmt, in welchem Kontext die verwendende Funktion definiert wird, sondern wie sie aufgerufen wird.

Die verschiedenen Varianten für Funktionsaufrufe, teilweise mit der Unterstützung von Hilfsmitteln wie call und apply, sind Gegenstand unzähliger Blogeinträge und Tutorials. Selbst das MDN (Mozilla Developer Network) widmet dem Schlüsselwort einen umfangreichen Eintrag, der sich mit der Abgrenzung zur Semantik in anderen Sprachen widmet:

"A function's this keyword behaves a little differently in JavaScript compared to other languages."

Die Einführung von Lambda-Ausdrücken in ECMAScript 2015 hat das Problem deutlich entschärft: An die Stelle von

const container = {
value: 23,

print () {
const that = this;

setTimeout(function () {
console.log(that.value);
}, 0.1 * 1000);
}
};

tritt nun der einfachere und zugleich kürzere folgende Code:

const container = {
value: 23,

print () {
setTimeout(() => {
console.log(this.value);
}, 0.1 * 1000);
}
};

Der Trick an der Stelle besteht darin, dass der Lambda-Ausdruck kein eigenes this erhält, sondern das bestehende, äußere this lexikalisch bindet. Genau das besagt auch die Spezifikation von JavaScript in Abschnitt 14.2.16:

"An ArrowFunction does not define local bindings for arguments, super, this, or new.target. Any reference to arguments, super, this, or new.target within an ArrowFunction must resolve to a binding in a lexically enclosing environment."

Daraus ergibt sich nun aber eine Besonderheit von Lambda-Ausdrücken, die nur wenigen Entwicklern bewusst ist: Da sich der Verweis unter anderem auf this gemäß der Spezifikation per Definition auf die lexikalische Umgebung beziehen muss, ist es nicht möglich, den Wert von this eines Lambda-Ausdrucks künstlich zu verändern, beispielsweise durch den Aufruf von bind.

Ein entsprechender Aufruf der bind-Funktion bleibt – unter Umständen wider Erwarten – wirkungslos (selbstverständlich lassen sich alle anderen Werte eines Lambda-Ausdrucks per bind belegen, nur für this gelingt das eben nicht).

Zugegebenermaßen befindet man sich eher selten in einer Situation, in der man das Binden eines Lambda-Ausdrucks versucht durchzuführen. Doch wenn, dann ist es enorm hilfreich zu wissen, dass das nicht funktioniert, und vor allem auch, warum nicht.

tl;dr: Lambda-Ausdrücke vereinfachen die Handhabung von this in JavaScript, bringen aber ihrerseits einige Besonderheiten mit, die unter Umständen unerwartet sind. Eine dieser Besonderheiten ist die fehlende Möglichkeit, den Wert von this eines Lambda-Ausdrucks neu zu binden.