Mit bind, call und apply den Kontext in JavaScript meistern
About 3 min reading time
In meinem letzten Beitrag habe ich bewusst noch ein paar Dinge unterschlagen, die im Umgang mit this hilfreich sein können: bind, apply und call. Zum einen war der Artikel schon gefühlt lang genug und außerdem nutze ich die drei Methoden (so gut wie) nie. Da mich Tobias aber darauf hingewiesen hat, hole ich das Ganze hier nach.
Einer Methode einen Context zuweisen, mit bind
Bisher habe ich, wenn ich einer Funktion einen Kontext mitgeben wollen, ein wenig geschummelt. In meinem letzten Artikel habe ich this in einer anderen Variable gespeichert und diese dann in der Funktion genutzt.
Sehen wir uns das Beispiel aus dem letzten Artikel nochmal mit einer kleinen Veränderung an und versuchen dann, ohne that zu arbeiten:
const john = {
lyrics: 'Let is be, let it be',
sing() {
console.log(this.lyrics);
},
singLater() {
const that = this;
setTimeout(function () {
that.sing();
}, 1);
}
};
john.singLater(); // 🎵 Let is be, let it beMithilfe von bind erstellen wir nun eine neue Variable singWithContext und binden in dieser den aktuellen Kontext (this, was hier john ist) an die Funktion sing.
const john = {
lyrics: 'Let is be, let it be',
sing() {
console.log(this.lyrics);
},
singLater() {
const singWithContext = this.sing.bind(this);
setTimeout(function () {
singWithContext();
}, 1);
}
};
john.singLater(); // 🎵 Let is be, let it be
Das geht auch noch etwas kürzer:
const john = {
lyrics: 'Let is be, let it be',
sing() {
console.log(this.lyrics);
},
singLater() {
const singWithContext = this.sing.bind(this);
setTimeout(singWithContext, 1);
}
};
john.singLater(); // 🎵 Let is be, let it beMan kann bind auch noch nutzen, um sich Methoden von anderen Objekten zu „borgen“: Nehmen wir einmal das folgende Beispiel:
const farin = {
firstName: 'Farin',
lastName: 'Urlaub',
fullName: function () {
return `${this.firstName} ${this.lastName}`;
}
};
const bela = {
firstName: 'Bela B',
lastName: 'Felsenheimer'
};
console.log(farin.fullName()); // Farin UrlaubMittels bind können wir jetzt den Kontext von Farins fullName() ändern, um auch den Namen von Bela B auszugeben
const farin = {
firstName: 'Farin',
lastName: 'Urlaub',
fullName: function () {
return `${this.firstName} ${this.lastName}`;
}
};
const bela = {
firstName: 'Bela B',
lastName: 'Felsenheimer'
};
console.log(farin.fullName()); // Farin Urlaub
const belaBFullName = farin.fullName.bind(bela);
console.log(belaBFullName()); // Bela B Felsenheimer
An einem unbekannten Ort ruft jemand jetzt wahrscheinlich: "Das geht auch mit Vererbung!" und diese Person hat auch mehr oder weniger Recht. Wir nutzen hier aber JavaScript und damit eine (halbwegs) funktionale Programmiersprache und diese bietet uns halt Wege, die in anderen Programmiersprachen so nicht existieren.
apply und call
Jetzt ist es stellenweise auch etwas umständlich, die mit bind an einen Kontext gebundene Funktion immer in einer Variable speichern zu müssen.
const rod = {
firstName: 'Rod',
lastName: 'Gonzales'
};
function sing(lyrics) {
console.log(`${this.firstName} ${this.lastName}: ${lyrics}`);
}
const rodSings = sing.bind(rod);
rodSings('Das sind Dinge, von denen ich gar nichts wissen will'); // 🎵 Rod Gonzales: Das sind Dinge, von denen ich gar nichts wissen willMit apply und call können wir das etwas verkürzen
const rod = {
firstName: 'Rod',
lastName: 'Gonzales'
};
function sing(lyrics) {
console.log(`${this.firstName} ${this.lastName}: ${lyrics}`);
}
sing.call(rod, 'Das sind Dinge, von denen ich gar nichts wissen will'); // 🎵 Rod Gonzales: Das sind Dinge, von denen ich gar nichts wissen willBei call geben wir erst den Kontext an und dann alle Parameter, mit denen wir die Funktion aufrufen wollen.
const rod = {
firstName: 'Rod',
lastName: 'Gonzales'
};
function sing(lyrics) {
return console.log(`${this.firstName} ${this.lastName}: ${lyrics}`);
}
sing.apply(rod, ['Das sind Dinge, von denen ich gar nichts wissen will']); // 🎵 Rod Gonzales: Das sind Dinge, von denen ich gar nichts wissen willDer Unterschied zu apply ist minimal: apply erwartet als zweiten Parameter einen Array, der alle Parameter für einen Aufruf enthält.
Mit bind, apply und call, haben wir drei Möglichkeiten, den Kontext einer Funktion zu manipulieren. Das ist definitiv einfacher zu lesen als Hilfsvariablen wie that oder self zu nutzen. Ich selbst nutze die drei aber, wie erwähnt, selten. Dies liegt wahrscheinlich daran, dass ich eher funktional programmiere und Objekte bei mir meistens nur Daten enthalten.
Wie sieht Eure Erfahrung hier aus? Schlagt ihr Euch mit dem Kontext in Euren Programmen herum und setzt bind, apply und call ein oder geht es Euch wie mir? Schreibt mir gerne auf Mastodon.