call, apply und bind sind drei Methoden, die auf jedem Function-Object verfügbar sind. Alle drei setzen this explizit — sie sind das Werkzeug für Explicit-Binding (Regel 3 der this-Regeln). call und apply rufen die Funktion sofort auf, sie unterscheiden sich nur darin, wie Argumente übergeben werden. bind liefert eine neue Funktion mit fixiertem this und optionalen vorgebundenen Argumenten — die Grundlage für Partial Application. Mit Spread (...args) ist apply heute weitgehend ersetzbar — die drei Methoden bleiben trotzdem omnipräsent in Library-Code und Polyfills.
Function.prototype.call
call ruft die Funktion sofort auf, mit dem ersten Argument als this. Weitere Argumente werden als normale Parameter weitergegeben.
function gruss(salut, frage) {
console.log(`${salut}, ${this.name}! ${frage}`);
}
const user = { name: 'Anna' };
gruss.call(user, 'Hi', 'Wie geht\'s?');
// → 'Hi, Anna! Wie geht's?'
// Ohne call: this wäre undefined (strict)
// gruss('Hi', '?'); // TypeError beim this.nameHi, Anna! Wie geht's?call ist die direkteste Form von Explicit-Binding. Häufiger Anwendungsfall: eine Methode eines anderen Objects auf ein neues Object „leihen".
Function.prototype.apply
apply ist funktional identisch mit call, nur dass die Argumente als Array übergeben werden.
function gruss(salut, frage) {
console.log(`${salut}, ${this.name}! ${frage}`);
}
const user = { name: 'Bob' };
gruss.apply(user, ['Hey', 'Alles gut?']);
// → 'Hey, Bob! Alles gut?'Hey, Bob! Alles gut?Pre-ES2015 war apply der einzige Weg, ein Array dynamisch als Argument-Liste an eine Funktion zu übergeben — Math.max.apply(null, [1, 5, 3, 9, 2]) zum Beispiel. Heute ersetzt Spread-Syntax das fast überall: Math.max(...[1, 5, 3, 9, 2]).
call vs. apply — kompakte Übersicht
function summe(a, b, c) { return a + b + c; }
// call: Argumente einzeln, kommagetrennt
console.log(summe.call(null, 1, 2, 3)); // 6
// apply: Argumente als Array
console.log(summe.apply(null, [1, 2, 3])); // 6
// Spread (ES2015) ersetzt apply praktisch komplett
console.log(summe(...[1, 2, 3])); // 66
6
6Faustregel: kennt man die Argumente, call nutzen. Hat man ein Array, spread nutzen. apply ist heute nur noch für Legacy-Code relevant.
Function.prototype.bind
bind liefert eine neue Funktion, in der this permanent fixiert ist. Weitere übergebene Argumente werden vorgebunden (Partial Application).
function gruss(salut, name) {
return `${salut}, ${name}!`;
}
// Nur this binden
const grussFn = gruss.bind({}, 'Hi');
console.log(grussFn('Anna')); // 'Hi, Anna!'
// this UND erstes Argument binden
function multipliziere(a, b) { return a * b; }
const verdoppeln = multipliziere.bind(null, 2);
console.log(verdoppeln(5)); // 10
console.log(verdoppeln(7)); // 14Hi, Anna!
10
14Im Gegensatz zu call/apply ruft bind die Funktion nicht auf — die Rückgabe ist eine neue Funktion, die später aufgerufen werden kann.
Method-Borrowing — Methoden „leihen"
Ein klassischer Use-Case für call/apply: eine Methode eines Prototypen auf einem Object aufrufen, das diese Methode gar nicht hat.
// arguments ist Array-LIKE, hat aber keine .map()
function alle() {
// Array.prototype.map auf arguments anwenden
const verdoppelt = Array.prototype.map.call(arguments, x => x * 2);
return verdoppelt;
}
console.log(alle(1, 2, 3)); // [ 2, 4, 6 ]
// NodeList → Array via slice borrowing (Legacy-Pattern)
// const arr = Array.prototype.slice.call(nodeList);
// Modern: Array.from oder Spread
function modern(...args) {
return args.map(x => x * 2);
}
console.log(modern(1, 2, 3));[ 2, 4, 6 ]
[ 2, 4, 6 ]Das Pattern ist in Legacy-Code allgegenwärtig. Modern: Rest-Parameter (...args) oder Array.from() erreichen dasselbe deklarativer.
bind für Callbacks — this retten
Die häufigste Anwendung von bind: eine Object-Methode an einen Callback weitergeben, ohne this zu verlieren.
class Counter {
constructor() { this.wert = 0; }
tick() { this.wert++; console.log('wert =', this.wert); }
}
const c = new Counter();
// OHNE bind: this verloren
// setTimeout(c.tick, 10); // TypeError: Cannot read properties of undefined
// MIT bind
setTimeout(c.tick.bind(c), 10);
// Alternative: Arrow-Wrapper
setTimeout(() => c.tick(), 20);wert = 1
wert = 2Die Arrow-Wrapper-Variante ist heute oft die bevorzugte Form — sie ist expliziter, was passiert, und braucht keine bind-Konvention.
Partial Application mit bind
bind kann Argumente vorbinden — die übergebenen Argumente landen am Anfang der Parameter-Liste der neuen Funktion.
function logMit(level, message, ...details) {
const ts = new Date().toISOString();
console.log(`[${ts}] [${level}] ${message}`, ...details);
}
// Vorbinden des Levels
const info = logMit.bind(null, 'INFO');
const warn = logMit.bind(null, 'WARN');
const error = logMit.bind(null, 'ERROR');
info('Server gestartet', { port: 3000 });
warn('Cache voll');
error('DB-Verbindung weg');[2026-05-14T07:42:31.000Z] [INFO] Server gestartet { port: 3000 }
[2026-05-14T07:42:31.000Z] [WARN] Cache voll
[2026-05-14T07:42:31.000Z] [ERROR] DB-Verbindung wegDas ist die einfachste Form von Partial Application — Detail-Behandlung im Currying-Artikel.
bind und new — Hard-Binding kann new nicht überschreiben
Wichtige Spec-Eigenheit: wenn eine bind-Funktion mit new aufgerufen wird, ignoriert der Constructor-Aufruf das gebundene this.
function Auto(marke) { this.marke = marke; }
const fester = { marke: 'fix' };
const Gebunden = Auto.bind(fester);
// Normaler Aufruf: bind wirkt
Gebunden('VW');
console.log(fester); // { marke: 'VW' } — fester wurde mutiert
// Mit new: bind wird ignoriert
const neu = new Gebunden('BMW');
console.log(neu); // Auto { marke: 'BMW' } — neues Object, bind hatte keinen Einfluss{ marke: 'VW' }
Auto { marke: 'BMW' }new ist die höchste Binding-Priorität und schlägt bind. Vorgebundene Argumente bleiben aber wirksam.
Polyfill-Skizzen
Zum besseren Verständnis: vereinfachte Implementationen.
// call selbst implementiert
Function.prototype.myCall = function(ctx, ...args) {
const sym = Symbol('fn');
ctx[sym] = this; // Funktion als Methode anhängen
const result = ctx[sym](...args);
delete ctx[sym];
return result;
};
// bind selbst implementiert
Function.prototype.myBind = function(ctx, ...vorbind) {
const fn = this;
return function(...rest) {
return fn.myCall(ctx, ...vorbind, ...rest);
};
};
function gruss(salut, name) { return `${salut}, ${this.titel} ${name}`; }
const user = { titel: 'Frau' };
console.log(gruss.myCall(user, 'Hi', 'Anna'));
const grHi = gruss.myBind(user, 'Hi');
console.log(grHi('Bob'));Hi, Frau Anna
Hi, Frau BobDie echten Implementations sind komplexer (Edge-Cases mit primitives, sloppy/strict, length-Property), aber das Pattern ist hier sichtbar. Symbol als Property-Key vermeidet Konflikte mit existierenden Methoden.
Arrows ignorieren call/apply/bind
Wichtige Erinnerung: Arrow Functions haben kein eigenes this. Alle drei Methoden — call, apply, bind — können das nicht ändern.
const arrow = () => this?.name;
console.log(arrow.call({ name: 'A' })); // undefined (lexical this)
const gebunden = arrow.bind({ name: 'B' });
console.log(gebunden()); // undefined
// Argumente vorbinden funktioniert aber schon:
const arrow2 = (x, y) => x + y;
const plus5 = arrow2.bind(null, 5);
console.log(plus5(3)); // 8undefined
undefined
8Daher: wenn Code via call/apply oder bind this setzen will, muss die Ziel-Funktion klassisch sein.
FAQ
Wann call, wann apply, wann bind?
call: ich kenne die Argumente einzeln und will sofort aufrufen. apply: ich habe ein Array von Argumenten — heute meist durch fn(...arr) mit Spread ersetzt. bind: ich will eine neue Funktion mit fixiertem this oder vorgebundenen Argumenten.
Warum ersetzt Spread apply nicht komplett?
fn(...arr) ersetzt fn.apply(null, arr) — aber Spread alleine setzt KEIN this. Wenn beides nötig ist (this UND Array-Argumente), gibt es zwei Wege: fn.call(ctx, ...arr) oder fn.apply(ctx, arr). call mit Spread ist die moderne Form.
Was passiert bei bind ohne Argumente?
fn.bind() ohne Argument liefert eine Funktion mit this = undefined (in Strict). In Sloppy wäre es globalThis. Praktisch nutzt das niemand — wenn man bind aufruft, übergibt man mindestens einen ctx-Wert.
Kann ich bind zweimal hintereinander aufrufen?
Spec-Verhalten: das zweite bind hat KEINEN Effekt auf this. fn.bind(a).bind(b) behält this = a. Argumente kann man aber weiterhin nachschieben: fn.bind(a, 1).bind(null, 2) bindet erst 1, dann 2 dazu. bind erzeugt jedes Mal eine neue Funktion.
Funktioniert call auf primitives als this?
fn.call(5) in Sloppy Mode boxt die 5 zu Number(5) als this. In Strict Mode bleibt es als 5 (Primitive). Daher: in Strict-mode-Code (ESM, class) keine versteckte Boxing-Magie. Meistens kein Thema — man übergibt typischerweise Object-Werte.
bind verändert das Original nicht — immer eine neue Funktion
const bound = fn.bind(obj) liefert eine neue Funktion. fn selbst bleibt unverändert — kann weiterhin mit anderem this aufgerufen werden. Das macht bind sicher und seiteneffekt-frei.
bind hat einen kleinen Performance-Overhead
Jede bind-Funktion ist ein Wrapper-Object mit eigener Identity. In sehr Hot-Loops (Millionen Aufrufe pro Sekunde) kann das spürbar sein. In Normal-Code ist es unmessbar. Wer Performance braucht und das gleiche this/Argument oft binden will, kann auch eine geschlossene Funktion definieren.
Reflect.apply als modernerer Ersatz für apply
Reflect.apply(fn, ctx, args) ist seit ES2015 spezifiziert und entspricht funktional fn.apply(ctx, args). Vorteil: man muss fn.apply nicht erst lookup-en, falls jemand fn.apply überschrieben hat. In Library-Code gelegentlich gesehen — in Anwendungs-Code praktisch identisch zu apply.
Weiterführende Ressourcen
Externe Quellen
- Function.prototype.call – MDN
- Function.prototype.apply – MDN
- Function.prototype.bind – MDN
- Function.prototype.call – ECMAScript Spec
- Reflect.apply – MDN