call, apply und bind

Javascript Funktionen: das Konzept von call, apply und bind

Jede Funktion hat Zugriff auf .apply(), .bind() und .call(). call, apply und bind borgen Funktionalität von anderen Objekten.

.bind(), wenn eine Funktion später in einem bestimmten Kontext aufgerufen werden soll (z.B. bei Events),
.call() oder .apply(), wenn eine Funktion sofort aufgerufen werden soll und den Kontext ändert.

function.call

Das einfach Objekt satz1 hat keine Methoden, die Methode mwst hat keine Eigenschaft num, gibt aber this.num zurück.

let satz1 = { num:19 };

let mwst = function (a) {
   return this.num * a / 100; 
}

mwst.call( satz1, 100);

Das Ergebnis des Aufrufs mwst.call( satz1, 100) ist 19. Die Funktion könnte genauso für ein zweites Objekt satz2 = { num:11 } aufgerufen werden.

19

Wenn die Funktion mehrere Parameter hat, werden sie allesamt im call-Aufruf aufgeführt.

let obj = { num: 2 };
let sum = function (a, b, c) {
   return this.num + a + b + c; 
}

sum.call( obj, 4, 6, 8);

Das Ergebnis wäre wie erwartet

20

Ein call-Aufruf mit einem Objekt, das mehrere Elemente hat:

let obj = { a: 2, b: 8 };
let sum = function (c) {
   console.log (this.a + this.b + c);
}

sum.call ( obj, 3);
13

function.apply

Anstelle der drei Parameter könnte ein Array übergeben werden, dann wäre der Aufruf apply anstelle von call.

let obj = { num:2 };
let arr = [3, 5, 9];
let add = function (a, b, c) {
   //console.log ("apply " + this.num + a + b + c);
}
add.apply( obj, arr);

function.bind

bind anstelle von apply würde die Funktion zurückgeben. function.bind führt die Funktion nicht aus, sondern gibt eine Funktion zurück, die später ausgeführt werden kann – z.B., wenn später ein Event eintritt.

So bleibt der Kontext in asynchronen Callbacks und Events erhalten.

let obj = { num: 3 };
let arr = [7, 13, 17];

let add = function (a, b, c) {
   //return this.num + a + b + c; 
   console.log (" bind *** " + this.num + a + b + c);
}

add.bind( obj, arr);
[Log] " bounded function addToThis() {↵    [native code]↵}" 

Jedes Javascript-Objekt hat einen Prototyp und in diesem Prototyp liegen Methoden, die nur für dieses Objekt benutzt werden können. Das kann man sich in der Console ansehen, z.B. anhand von Array.

console.dir ([]);
▼ Array(0)
  length: 0
  ▼__proto__: Array(0)
     ▶concat:ƒ concat()
     ▶constructor:ƒ Array()
     ▶copyWithin:ƒ copyWithin()
     ▶entries:ƒ entries()
     ▶every:ƒ every()
     ▶fill:ƒ fill()
     ▶filter:ƒ filter()
     ▶find:ƒ find()
     ▶findIndex:ƒ findIndex()
     ▶forEach:ƒ forEach()
     ▶includes:ƒ includes()
     ▶indexOf:ƒ indexOf()
     ▶join:ƒ join()
     ▶keys:ƒ keys()
     ▶lastIndexOf:ƒ lastIndexOf()
     ▶length:0
     ▶map:ƒ map()
     ▶pop:ƒ pop()
     ▶push:ƒ push()
     ▶reduce:ƒ reduce()
     ▶reduceRight:ƒ reduceRight()
     ▶reverse:ƒ reverse()
     ▶shift:ƒ shift()
     ▶slice:ƒ slice()
     ▶some:ƒ some()
     ▶sort:ƒ sort()
     ▶splice:ƒ splice()
     ▶toLocaleString:ƒ toLocaleString()
     ▶toString:ƒ toString()
     ▶unshift:ƒ unshift()
     ▶Symbol(Symbol.iterator):ƒ values()
     ▶Symbol(Symbol.unscopables):
{copyWithin: true, entries: true, fill: true, find: true, findIndex: true, …}
__proto__
:
Object

Jedes Objekt hat ein Element arguments für alle Parameter, die übergeben werden können.

let argsToArray = function () {
   console.log (arguments);
}
argsToArray (1, 2, 3);

Der Aufruf gibt kein Array, sondern ein Objekt mit drei Elementen zurück, und hat keine Array-Methoden wie slice und trim.

Arguments(3) [1, 2, 3, callee: ƒ, Symbol(Symbol.iterator): ƒ]
   0: 1
   1: 2
   2: 3
   callee: ƒ ()
   length: 3
   Symbol(Symbol.iterator): ƒ values()
   __proto__: Object

Also leihen wir die Funktionalität vom Prototyp des Arrays mit einem call-Aufruf. [] ist ein leeres Array.

let argsToArray = function () {
   console.log ([].slice.call(arguments));
}
argsToArray(1,2,3)
call apply bind