JavaScript/Objekte/Function/bind

Aus SELFHTML-Wiki
Wechseln zu: Navigation, Suche

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])


Attribute
Writable true
Enumerable false
Configurable true


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:

Beispiel
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:

Beispiel
   ...
   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:

Beispiel
   ...
   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.

Beispiel
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.

Beispiel
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