JavaScript/Objekte/Function/bind
Die Methode bind wurde mit ECMAScript 5 eingeführt und dient dazu, den this
Wert einer Funktion und ggf. auch die ersten Argumente fest vorzugeben.
Syntax
Function.prototype.bind(thisArg[, args])
Writable | true |
Enumerable | false |
Configurable | true |
Inhaltsverzeichnis
Beschreibung
Festlegen von this
Wird die Methode bind
auf einem Funktionsobjekt aufgerufen, dann wird eine sogenannte gebundene Funktion erzeugt. Die gebundene Funktion ist ein neues Funktionsobjekt, das die an bind
übergebenen Parameter und das ursprüngliche Funktionsobjekt speichert. Ruft man die gebundene Funktion auf, so stellt sie das an bind
übergebene thisArg
der ursprünglichen Funktion als this
zur Verfügung.
Das kann man beispielsweise nutzen, wenn man eine Objektmethode als setTimeout Handler verwenden will:
var text = "Oops"; // var erzeugt eine globale Variable
const demoObject = {
signalWithDelay(text, delay) {
this.text = text;
setTimeout(this.signal, delay); // wird nicht funktionieren!
},
signal() {
console.log(this.text);
}
};
demoObject.signalWithDelay("Hallo Welt", 1000);
Das Beispiel gibt nach einer Sekunde den Text Oops aus. Grund dafür ist, dass signalWithDelay
den auszugebenden Text am Objekt speichert, dann aber lediglich das Funktionsobjekt der signal
-Methode an setTimeout
übergibt. Methoden sind zunächst einmal ungebunden, kennen also nicht das Objekt, zu dem sie gehören, und setTimeout
stellt einer Funktion als this
das window
-Objekt zur Verfügung. Darum greift this.text
in der signal
-Methode auf die zuvor definierte globale Variable text
zu (globale Variablen sind Eigenschaften des window
-Objekts).
Mit Hilfe von bind
kann man Abhilfe schaffen:
...
signalWithDelay(text, delay) {
this.text = text;
setTimeout(this.signal.bind(this), delay); // funktioniert
},
...
Jetzt bekommt setTimeout
die von bind(this)
erzeugte gebundene Funktion übergeben, und diese sorgt dafür, dass die signal
Methode mit dem gebundenen this
-Objekt aufgerufen wird.
Es soll nicht verschwiegen werden, dass dieser Ablauf mit neueren JavaScript-Features besser lesbar wird. Mit einer Pfeilfunktion könnte man das Beispiel so schreiben:
...
signalWithDelay(text, delay) {
this.text = text;
setTimeout(() => this.signal(text), delay); // funktioniert auch
},
...
„Pfeilfunktionen binden this
nicht neu“, heißt es an anderer Stelle im Wiki, deswegen gilt in der Pfeilfunktion das gleiche this
wie in der Funktion, in der sie definiert wurde. Das funktioniert aber nur deshalb, weil JavaScript hinter den Kulissen das Funktionsobjekt der Pfeilfunktion an das this
Objekt bindet, das in diesem Moment gültig ist.
Partieller Aufruf von Funktionen (currying)
Man kann an bind
noch weitere Argumente übergeben. Diese werden an die ersten Parameter der ursprünglichen Funktion gebunden. Die gebundene Funktion erwartet nur noch so viele Argumente, wie nicht gebunden werden konnten.
Um zu verdeutlichen, wie das abläuft, soll eine Funktion partialApply
gezeigt werden, die eine andere Funktion so einhüllt, dass die ersten Parameter dieser Funktion festgelegt werden. Auf die Festlegung von this
wird für die Übersichtlichkeit verzichtet.
Früher hätte das einiges Jonglieren mit Parameter-Arrays bedeutet, seit ECMAScript 2018 vereinfacht der Rest- und Spread-Operator ...
die Sache deutlich.
function partialApply(originalFunction, ...boundArgs) {
return function(...freeArgs) {
originalFunction(...boundArgs, ...freeArgs);
}
}
function addiere(a, b) {
return a + b;
}
// Bilde eine gebundene Funktion mit der 42 als teilweise angewendetem Parameter.
var addiere42 = partialApply(addiere, 42);
console.log(addiere42(5)); // gibt 47 aus
Die von partialApply
erzeugte anonyme Funktion bildet eine Closure um die Argumente von partialApply
. Wird diese Funktion aufgerufen, werden die Argumente aus dem partialApply
-Aufruf und die Argumente des eigenen Aufrufs mit Hilfe des Rest- und Spread-Operators der ursprünglichen Funktion zur Verfügung gestellt.
Als ein Einsatzbereich der partiellen Anwendung von Funktionsargumenten wird häufig das Currying genannt, einem Konzept funktionaler Programmiersprachen. Beachten Sie aber, dass Currying in JavaScript nur eine akademische Spielerei ist.
Ein mögliches Anwendungsbeispiel für gebundene Parameter wäre eine Funktion, die einen Eingabewert auf ein bestimmtes Maximum begrenzt. Dazu kann man einen Parameter von Math.min
(sic!) binden.
const maximal500 = Math.min.bind(null, 500);
// Ohne bind könnte man auch eine Pfeilfunktion schreiben
//const maximal500 = (wert) => Math.min(wert, 500);
console.log(maximal500(100)); // 100
console.log(maximal500(700)); // 500
Siehe auch
Weblinks
- ECMAScript 2015: Function.prototype.bind()