it-swarm.com.de

Was ist der Unterschied zwischen Anrufen und Anwenden?

Was ist der Unterschied zwischen der Verwendung von call und apply zum Aufrufen einer Funktion?

var func = function() {
  alert('hello!');
};

func.apply(); vs func.call();

Gibt es Leistungsunterschiede zwischen den beiden oben genannten Methoden? Wann ist es am besten, call anstelle von apply zu verwenden und umgekehrt?

2974
John Duff

Der Unterschied besteht darin, dass Sie mit apply die Funktion mit arguments als Array aufrufen können. call erfordert die explizite Auflistung der Parameter. Eine nützliche Mnemonik ist "A für a ray und C für c omma. "

Siehe MDN-Dokumentation zu anwenden und aufrufen .

Pseudosyntax:

theFunction.apply(valueForThis, arrayOfArgs)

theFunction.call(valueForThis, arg1, arg2, ...)

Ab ES6 besteht auch die Möglichkeit, spread das Array für die Verwendung mit der Funktion call zu verwenden. Sie können die Kompatibilitäten sehen hier .

Beispielcode:

function theFunction(name, profession) {
    console.log("My name is " + name + " and I am a " + profession +".");
}
theFunction("John", "fireman");
theFunction.apply(undefined, ["Susan", "school teacher"]);
theFunction.call(undefined, "Claude", "mathematician");
theFunction.call(undefined, ...["Matthew", "physicist"]); // used with the spread operator
3519
flatline

K. Scott Allen hat eine nette Beschreibung in der Sache.

Grundsätzlich unterscheiden sie sich im Umgang mit Funktionsargumenten.

Die Methode apply () ist mit call () identisch, außer dass apply () ein Array als zweiten Parameter benötigt. Das Array repräsentiert die Argumente für die Zielmethode. "

Damit:

// assuming you have f
function f(message) { ... }
f.call(receiver, "test");
f.apply(receiver, ["test"]);
220
notnoop

Verwenden Sie apply, wenn Sie die Anzahl der übergebenen Argumente nicht kennen oder wenn sie sich bereits in einem Array oder einem Array-ähnlichen Objekt befinden (z. B. arguments -Objekt, um Ihre eigenen Argumente weiterzuleiten.Verwenden Sie andernfalls call, da die Argumente nicht in ein Array eingeschlossen werden müssen.

f.call(thisObject, a, b, c); // Fixed number of arguments

f.apply(thisObject, arguments); // Forward this function's arguments

var args = [];
while (...) {
    args.Push(some_value());
}
f.apply(thisObject, args); // Unknown number of arguments

Wenn ich keine Argumente übergebe (wie in Ihrem Beispiel), bevorzuge ich call, da ich aufrufend die Funktion bin. apply bedeutet, dass Sie anwenden die Funktion auf die (nicht vorhandenen) Argumente anwenden.

Es sollte keine Leistungsunterschiede geben, außer wenn Sie apply verwenden und die Argumente in ein Array einschließen (z. B. f.apply(thisObject, [a, b, c]) anstelle von f.call(thisObject, a, b, c)). Ich habe es nicht getestet, es könnte also Unterschiede geben, aber es wäre sehr browserspezifisch. Es ist wahrscheinlich, dass call schneller ist, wenn Sie die Argumente noch nicht in einem Array haben, und apply ist schneller, wenn Sie dies tun.

153
Matthew Crumley

Hier ist eine gute Erinnerung. EINpply verwendet EINstrahlen und EINnimmt immer ein oder zwei Argumente. Wenn Sie verwenden Calles was du musst Czählen Sie die Anzahl der Argumente.

106
Joe

Während dies ein altes Thema ist, wollte ich nur darauf hinweisen, dass .call etwas schneller ist als .apply. Ich kann dir nicht genau sagen warum.

Siehe jsPerf, http://jsperf.com/test-call-vs-apply/


[UPDATE!]

Douglas Crockford erwähnt kurz den Unterschied zwischen den beiden, was den Leistungsunterschied erklären kann ... http://youtu.be/ya4UHuXNygM?t=15m52s

Apply akzeptiert eine Reihe von Argumenten, während Call keine oder mehrere einzelne Parameter akzeptiert! Ah hah!

.apply(this, [...])

.call(this, param1, param2, param3, param4...)

91
kmatheny

Es folgt ein Auszug aus Abschluss: The Definitive Guide von Michael Bolin . Es mag ein bisschen langweilig aussehen, aber es steckt voller Einsichten. Aus "Anhang B. Häufig missverstandene JavaScript-Konzepte":


Was this bezeichnet, wenn eine Funktion aufgerufen wird

Beim Aufruf einer Funktion der Form foo.bar.baz() wird das Objekt foo.bar als Empfänger bezeichnet. Wenn die Funktion aufgerufen wird, wird der Empfänger als Wert für this verwendet:

var obj = {};
obj.value = 10;
/** @param {...number} additionalValues */
obj.addValues = function(additionalValues) {
  for (var i = 0; i < arguments.length; i++) {
    this.value += arguments[i];
  }
  return this.value;
};
// Evaluates to 30 because obj is used as the value for 'this' when
// obj.addValues() is called, so obj.value becomes 10 + 20.
obj.addValues(20);

Wenn beim Aufruf einer Funktion kein expliziter Empfänger vorhanden ist, wird das globale Objekt zum Empfänger. Wie in "goog.global" auf Seite 47 erläutert, ist window das globale Objekt, wenn JavaScript in einem Webbrowser ausgeführt wird. Dies führt zu einem überraschenden Verhalten:

var f = obj.addValues;
// Evaluates to NaN because window is used as the value for 'this' when
// f() is called. Because and window.value is undefined, adding a number to
// it results in NaN.
f(20);
// This also has the unintentional side effect of adding a value to window:
alert(window.value); // Alerts NaN

Obwohl obj.addValues und f sich auf dieselbe Funktion beziehen, verhalten sie sich beim Aufruf unterschiedlich, da der Wert des Empfängers bei jedem Aufruf unterschiedlich ist. Aus diesem Grund muss beim Aufrufen einer Funktion, die auf this verweist, sichergestellt werden, dass this beim Aufrufen den richtigen Wert hat. Um klar zu sein, wenn this nicht im Funktionskörper referenziert würde, dann wäre das Verhalten von f(20) und obj.addValues(20) dasselbe.

Da Funktionen in JavaScript erstklassige Objekte sind, können sie ihre eigenen Methoden haben. Alle Funktionen haben die Methoden call() und apply(), die es ermöglichen, den Empfänger (d. H. Das Objekt, auf das this verweist) beim Aufrufen der Funktion neu zu definieren. Die Methodensignaturen lauten wie folgt:

/**
* @param {*=} receiver to substitute for 'this'
* @param {...} parameters to use as arguments to the function
*/
Function.prototype.call;
/**
* @param {*=} receiver to substitute for 'this'
* @param {Array} parameters to use as arguments to the function
*/
Function.prototype.apply;

Beachten Sie, dass der einzige Unterschied zwischen call() und apply() darin besteht, dass call() die Funktionsparameter als einzelne Argumente empfängt, während apply() sie als einzelnes Array empfängt:

// When f is called with obj as its receiver, it behaves the same as calling
// obj.addValues(). Both of the following increase obj.value by 60:
f.call(obj, 10, 20, 30);
f.apply(obj, [10, 20, 30]);

Die folgenden Aufrufe sind äquivalent, da f und obj.addValues sich auf dieselbe Funktion beziehen:

obj.addValues.call(obj, 10, 20, 30);
obj.addValues.apply(obj, [10, 20, 30]);

Da jedoch weder call() noch apply() den Wert seines eigenen Empfängers verwenden, um das Empfängerargument zu ersetzen, wenn es nicht angegeben ist, funktioniert Folgendes nicht:

// Both statements evaluate to NaN
obj.addValues.call(undefined, 10, 20, 30);
obj.addValues.apply(undefined, [10, 20, 30]);

Der Wert von this kann niemals null oder undefined sein, wenn eine Funktion aufgerufen wird. Wenn null oder undefined als Empfänger an call() oder apply() übergeben wird, wird stattdessen das globale Objekt als Wert für den Empfänger verwendet. Daher hat der vorherige Code den gleichen unerwünschten Nebeneffekt beim Hinzufügen einer Eigenschaft mit dem Namen value zum globalen Objekt.

Es kann hilfreich sein, sich eine Funktion so vorzustellen, dass sie die Variable, der sie zugewiesen ist, nicht kennt. Dies verstärkt die Vorstellung, dass der Wert dieser Funktion gebunden wird, wenn die Funktion aufgerufen wird, und nicht, wenn sie definiert wird.


Ende des Auszuges.

75

Manchmal ist es nützlich, wenn ein Objekt die Funktion eines anderen Objekts ausleiht, dh, das ausleihende Objekt führt die ausgeliehene Funktion einfach so aus, als wäre es seine eigene.

Ein kleines Codebeispiel:

var friend = {
    car: false,
    lendCar: function ( canLend ){
      this.car = canLend;
 }

}; 

var me = {
    car: false,
    gotCar: function(){
      return this.car === true;
  }
};

console.log(me.gotCar()); // false

friend.lendCar.call(me, true); 

console.log(me.gotCar()); // true

friend.lendCar.apply(me, [false]);

console.log(me.gotCar()); // false

Diese Methoden sind sehr nützlich, um Objekten temporäre Funktionen zu geben.

33
tjacks3

Ein weiteres Beispiel mit Call, Apply und Bind. Der Unterschied zwischen Call und Apply ist offensichtlich, aber Bind funktioniert wie folgt:

  1. Bind gibt eine Instanz einer Funktion zurück, die ausgeführt werden kann
  2. Erster Parameter ist ' this '
  3. Zweiter Parameter ist eine durch Kommas getrennte Liste von Argumenten (wie Aufruf )

}

function Person(name) {
    this.name = name; 
}
Person.prototype.getName = function(a,b) { 
     return this.name + " " + a + " " + b; 
}

var reader = new Person('John Smith');

reader.getName = function() {
   // Apply and Call executes the function and returns value

   // Also notice the different ways of extracting 'getName' prototype
   var baseName = Object.getPrototypeOf(this).getName.apply(this,["is a", "boy"]);
   console.log("Apply: " + baseName);

   var baseName = Object.getPrototypeOf(reader).getName.call(this, "is a", "boy"); 
   console.log("Call: " + baseName);

   // Bind returns function which can be invoked
   var baseName = Person.prototype.getName.bind(this, "is a", "boy"); 
   console.log("Bind: " + baseName());
}

reader.getName();
/* Output
Apply: John Smith is a boy
Call: John Smith is a boy
Bind: John Smith is a boy
*/
25
Mahesh

Ich möchte ein Beispiel zeigen, in dem das Argument 'valueForThis' verwendet wird:

Array.prototype.Push = function(element) {
   /*
   Native code*, that uses 'this'       
   this.put(element);
   */
}
var array = [];
array.Push(1);
array.Push.apply(array,[2,3]);
Array.prototype.Push.apply(array,[4,5]);
array.Push.call(array,6,7);
Array.prototype.Push.call(array,8,9);
//[1, 2, 3, 4, 5, 6, 7, 8, 9] 

** Details: http://es5.github.io/#x15.4.4.7 *

23
user669677

Call () akzeptiert durch Kommas getrennte Argumente, zum Beispiel:

.call(scope, arg1, arg2, arg3)

und apply () verwendet eine Reihe von Argumenten, z.

.apply(scope, [arg1, arg2, arg3])

hier einige weitere Verwendungsbeispiele: http://blog.i-evaluation.com/2012/08/15/javascript-call-and-apply/

20
Mark Karwowski

Ab dokumentiert das MDN auf Function.prototype.apply () :

Die Methode apply () ruft eine Funktion mit einem bestimmten this -Wert und Argumenten auf, die als Array (oder Array-ähnliches Objekt) bereitgestellt werden.

Syntax

fun.apply(thisArg, [argsArray])

Ab dokumentiert das MDN auf Function.prototype.call () :

Die call () -Methode ruft eine Funktion mit einem bestimmten this -Wert und Argumenten auf, die einzeln angegeben werden.

Syntax

fun.call(thisArg[, arg1[, arg2[, ...]]])

Von Function.apply und Function.call in JavaScript :

Die Methode apply () ist mit call () identisch, außer dass apply () ein Array als zweiten Parameter benötigt. Das Array repräsentiert die Argumente für die Zielmethode.


Codebeispiel:

var doSomething = function() {
    var arr = [];
    for(i in arguments) {
        if(typeof this[arguments[i]] !== 'undefined') {
            arr.Push(this[arguments[i]]);
        }
    }
    return arr;
}

var output = function(position, obj) {
    document.body.innerHTML += '<h3>output ' + position + '</h3>' + JSON.stringify(obj) + '\n<br>\n<br><hr>';
}

output(1, doSomething(
    'one',
    'two',
    'two',
    'one'
));

output(2, doSomething.apply({one : 'Steven', two : 'Jane'}, [
    'one',
    'two',
    'two',
    'one'
]));

output(3, doSomething.call({one : 'Steven', two : 'Jane'},
    'one',
    'two',
    'two',
    'one'
));

Siehe auch this Fiddle .

19
John Slegers

Der grundlegende Unterschied besteht darin, dass call() eine Argumentliste akzeptiert, während apply() akzeptiert ein einzelnes Array von Argumenten .

11
Rakesh Kumar

Hier ist ein kleiner Beitrag, den ich dazu geschrieben habe:

http://sizeableidea.com/call-versus-apply-javascript/

var obj1 = { which : "obj1" },
obj2 = { which : "obj2" };

function execute(arg1, arg2){
    console.log(this.which, arg1, arg2);
}

//using call
execute.call(obj1, "dan", "stanhope");
//output: obj1 dan stanhope

//using apply
execute.apply(obj2, ["dan", "stanhope"]);
//output: obj2 dan stanhope

//using old school
execute("dan", "stanhope");
//output: undefined "dan" "stanhope"
10
Dan

Der Unterschied besteht darin, dass call() die Funktionsargumente separat und apply() die Funktionsargumente in einem Array verwendet.

7
Sanjib Debnath

Wir können Call- und Apply-Methoden wie folgt unterscheiden

CALL: Eine Funktion mit Argument, die einzeln bereitgestellt wird. Wenn Sie die zu übergebenden Argumente kennen oder keine Argumente vorhanden sind, können Sie call verwenden.

APPLY: Ruft eine Funktion mit einem als Array angegebenen Argument auf. Sie können apply verwenden, wenn Sie nicht wissen, wie viele Argumente an die Funktion übergeben werden.

Es ist von Vorteil, Apply over Call zu verwenden. Wir müssen nicht die Anzahl der Argumente ändern, sondern können nur ein Array ändern, das übergeben wird.

Es gibt keinen großen Leistungsunterschied. Wir können jedoch sagen, dass der Aufruf etwas schneller ist als der Vergleich, um ihn anzuwenden, da ein Array in der Methode apply ausgewertet werden muss.

6
Praveen D

Aufruf und Anwenden beider werden verwendet, um den this -Wert zu erzwingen, wenn eine Funktion ausgeführt wird. Der einzige Unterschied besteht darin, dass calln+1 Argumente akzeptiert, wobei 1 this und 'n' arguments ist. apply akzeptiert nur zwei Argumente, eines ist this das andere ist ein Argumentarray.

Der Vorteil, den ich in apply gegenüber call sehe, besteht darin, dass wir einen Funktionsaufruf ohne großen Aufwand einfach an eine andere Funktion delegieren können.

function sayHello() {
  console.log(this, arguments);
}

function hello() {
  sayHello.apply(this, arguments);
}

var obj = {name: 'my name'}
hello.call(obj, 'some', 'arguments');

Beobachten Sie, wie einfach es ist, hello mit sayHello an apply zu delegieren, aber mit call ist dies sehr schwer zu erreichen.

5
Raghavendra

Der Unterschied zwischen diesen Methoden besteht darin, wie Sie die Parameter übergeben möchten.

"A für Array und C für Komma" ist eine praktische Mnemonik.

5
venkat7668

Obwohl call und apply dasselbe erreichen, gibt es meines Erachtens mindestens einen Ort, an dem Sie call nicht verwenden können, sondern nur apply. In diesem Fall möchten Sie die Vererbung unterstützen und den Konstruktor aufrufen.

Mit dieser Funktion können Sie Klassen erstellen, die auch das Erstellen von Klassen durch Erweitern anderer Klassen unterstützen.

function makeClass( properties ) {
    var ctor = properties['constructor'] || function(){}
    var Super = properties['extends'];
    var Class = function () {
                 // Here 'call' cannot work, only 'apply' can!!!
                 if(Super)
                    Super.apply(this,arguments);  
                 ctor.apply(this,arguments);
                }
     if(Super){
        Class.prototype = Object.create( Super.prototype );
        Class.prototype.constructor = Class;
     }
     Object.keys(properties).forEach( function(prop) {
           if(prop!=='constructor' && prop!=='extends')
            Class.prototype[prop] = properties[prop];
     });
   return Class; 
}

//Usage
var Car = makeClass({
             constructor: function(name){
                         this.name=name;
                        },
             yourName: function() {
                     return this.name;
                   }
          });
//We have a Car class now
 var carInstance=new Car('Fiat');
carInstance.youName();// ReturnsFiat

var SuperCar = makeClass({
               constructor: function(ignore,power){
                     this.power=power;
                  },
               extends:Car,
               yourPower: function() {
                    return this.power;
                  }
              });
//We have a SuperCar class now, which is subclass of Car
var superCar=new SuperCar('BMW xy',2.6);
superCar.yourName();//Returns BMW xy
superCar.yourPower();// Returns 2.6
4

Der Hauptunterschied besteht darin, dass wir mit call den Gültigkeitsbereich ändern und Argumente wie gewohnt übergeben können. Mit apply können Sie ihn jedoch mit Argumenten als Array aufrufen (als Array übergeben). In Bezug auf das, was sie in Ihrem Code tun sollen, sind sie sich jedoch ziemlich ähnlich.

Während die Syntax dieser Funktion fast mit der von apply () identisch ist, besteht der grundlegende Unterschied darin, dass call () eine Argumentliste akzeptiert, während apply () ein einzelnes Array von Argumenten akzeptiert.

Wie Sie sehen, gibt es keinen großen Unterschied, aber es gibt Fälle, in denen wir call () oder apply () bevorzugen. Betrachten Sie beispielsweise den folgenden Code, der die kleinste und größte Zahl in einem Array von MDN mithilfe der Methode apply ermittelt:

// min/max number in an array
var numbers = [5, 6, 2, 3, 7];

// using Math.min/Math.max apply
var max = Math.max.apply(null, numbers); 
// This about equal to Math.max(numbers[0], ...)
// or Math.max(5, 6, ...)

var min = Math.min.apply(null, numbers)

Der Hauptunterschied besteht also darin, wie wir die Argumente weitergeben:

Anruf:

function.call(thisArg, arg1, arg2, ...);

Anwenden:

function.apply(thisArg, [argsArray]);
4
Alireza

Zusammenfassung:

Sowohl call() als auch apply() sind Methoden, die sich auf Function.prototype befinden. Daher sind sie über die Prototypenkette auf jedem Funktionsobjekt verfügbar. Sowohl call() als auch apply() können eine Funktion mit einem bestimmten Wert von this ausführen.

Der Hauptunterschied zwischen call() und apply() ist die Art und Weise, wie Argumente übergeben werden müssen. In call() und apply() übergeben Sie als erstes Argument das Objekt, dessen Wert this sein soll. Die anderen Argumente unterscheiden sich folgendermaßen:

  • Mit call() müssen Sie die Argumente normal eingeben (ab dem zweiten Argument)
  • Mit apply() müssen Sie eine Reihe von Argumenten übergeben.

Beispiel:

let obj = {
  val1: 5,
  val2: 10
}

const summation = function (val3, val4) {
  return  this.val1 + this.val2 + val3 + val4;
}

console.log(summation.apply(obj, [2 ,3]));
// first we assign we value of this in the first arg
// with apply we have to pass in an array


console.log(summation.call(obj, 2, 3));
// with call we can pass in each arg individually

Warum sollte ich diese Funktionen nutzen müssen?

Der Wert this kann in Javascript manchmal schwierig sein. Der Wert von this wird bestimmt wenn eine Funktion ausgeführt wird, nicht wenn eine Funktion definiert ist. Wenn unsere Funktion von einer richtigen this Bindung abhängt, können wir call() verwenden. und apply(), um dieses Verhalten zu erzwingen. Zum Beispiel:

var name = 'unwantedGlobalName';

const obj =  {
  name: 'Willem',
  sayName () { console.log(this.name);}
}


let copiedMethod = obj.sayName;
// we store the function in the copiedmethod variable



copiedMethod();
// this is now window, unwantedGlobalName gets logged

copiedMethod.call(obj);
// we enforce this to be obj, Willem gets logged
3