Vraag Wat is het verschil tussen bellen en solliciteren?


Wat is het verschil tussen gebruik call en apply om een ​​functie aan te roepen?

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

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

Zijn er prestatieverschillen tussen de twee bovengenoemde methoden? Wanneer is het het beste om te gebruiken call over- apply en vice versa?


2737
2017-12-31 19:56


oorsprong


antwoorden:


Het verschil is dat apply laat je de functie oproepen met arguments als een array; call vereist dat de parameters expliciet worden vermeld. Een handige mnemonic is "EEN voor eenrray en C voor cOMMA."

Zie de documentatie van MDN op van toepassing zijn en telefoontje.

Pseudo-syntaxis:

theFunction.apply(valueForThis, arrayOfArgs)

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

Er is ook, vanaf ES6, de mogelijkheid om spread de array voor gebruik met de call functie, kunt u de compatibiliteit zien hier.

Voorbeeldcode:

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


3304
2017-12-31 20:00



K. Scott Allen heeft een mooie beschrijving over de kwestie.

Kortom, ze verschillen over hoe ze omgaan met functieargumenten.

De methode apply () is identiek aan call (), behalve apply () vereist een array als de tweede parameter. De array vertegenwoordigt de argumenten voor de doelmethode. "

Zo:

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

209
2017-12-31 19:59



Gebruik de functie om het deel over het gebruik van elke functie te beantwoorden apply als u niet weet hoeveel argumenten u doorgeeft, of als ze al in een array of array-achtig object staan ​​(zoals de arguments object om je eigen argumenten door te sturen. Gebruik call anders, omdat het niet nodig is om de argumenten in een array in te pakken.

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

Wanneer ik geen argumenten doorgeef (zoals je voorbeeld), heb ik de voorkeur call sinds ik ben roeping de functie. apply zou impliceren dat je dat bent toepassen de functie van de (niet-bestaande) argumenten.

Er mogen geen prestatieverschillen zijn, behalve misschien als u gebruikt apply en wikkel de argumenten in een array (bijv. f.apply(thisObject, [a, b, c]) in plaats van f.call(thisObject, a, b, c)). Ik heb het niet getest, dus er kunnen verschillen zijn, maar het zou erg browser-specifiek zijn. Het is waarschijnlijk dat call is sneller als je de argumenten niet al in een array hebt en apply is sneller als je dat doet.


150
2017-12-31 21:50



Hier is een goed geheugensteuntje. EENpply gebruikt EENrrays en EENneemt altijd een of twee argumenten. Wanneer je gebruikt Calles wat je moet doen Count het aantal argumenten.


102
2017-09-04 13:36



Hoewel dit een oud onderwerp is, wilde ik er alleen op wijzen dat .call iets sneller is dan .apply. Ik kan je niet precies vertellen waarom.

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


[UPDATE!]

Douglas Crockford vermeldt kort het verschil tussen de twee, wat het prestatieverschil kan helpen verklaren ... http://youtu.be/ya4UHuXNygM?t=15m52s

Toepassen neemt een reeks argumenten in beslag, terwijl Call nul of meer individuele parameters aanneemt! Ah hah!

.apply(this, [...])

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


91
2017-11-07 17:36



Volgt een uittreksel van Sluiting: de definitieve gids door Michael Bolin. Het ziet er misschien een beetje lang uit, maar het is doordrenkt met veel inzicht. Uit "Bijlage B. Veel verkeerd begrepen JavaScript-concepten":


Wat this Verwijst naar wanneer een functie wordt aangeroepen

Bij het aanroepen van een functie van het formulier foo.bar.baz(), het object foo.bar wordt de ontvanger genoemd. Wanneer de functie wordt aangeroepen, is dit de ontvanger die als waarde voor wordt gebruikt this:

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

Als er geen expliciete ontvanger is wanneer een functie wordt aangeroepen, wordt het globale object de ontvanger. Zoals uitgelegd in "goog.global" op pagina 47, is het venster het globale object wanneer JavaScript wordt uitgevoerd in een webbrowser. Dit leidt tot een verrassend gedrag:

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

Hoewel obj.addValues en f verwijzen naar dezelfde functie, ze gedragen zich anders wanneer ze worden gebeld omdat de waarde van de ontvanger bij elk gesprek anders is. Om deze reden wanneer u een functie aanroept waarnaar wordt verwezen this, het is belangrijk om dat te garanderen this zal de juiste waarde hebben wanneer deze wordt opgeroepen. Voor de duidelijkheid, als this er werd niet naar verwezen in de functie body, dan is het gedrag van f(20) en obj.addValues(20) zou hetzelfde zijn.

Omdat functies eersteklas objecten in JavaScript zijn, kunnen ze hun eigen methoden hebben. Alle functies hebben de methoden call() en apply() die het mogelijk maken om de ontvanger opnieuw te definiëren (d.w.z. het object dat this verwijst naar) bij het aanroepen van de functie. De handtekeningen van de methode zijn als volgt:

/**
* @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;

Merk op dat het enige verschil tussen call() en apply() is dat call() ontvangt de functieparameters als individuele argumenten, terwijl apply() ontvangt ze als een enkele array:

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

De volgende oproepen zijn equivalent, zoals f en obj.addValues refereer naar dezelfde functie:

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

Echter, aangezien geen van beide call() noch apply() gebruikt de waarde van zijn eigen ontvanger om het argument van de ontvanger te vervangen wanneer het niet gespecificeerd is, het volgende zal niet werken:

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

De waarde van this kan nooit zijn null of undefined wanneer een functie wordt aangeroepen. Wanneer null of undefined wordt geleverd als ontvanger voor call() of apply(), het globale object wordt in plaats daarvan gebruikt als de waarde voor de ontvanger. Daarom heeft de vorige code hetzelfde ongewenste neveneffect van het toevoegen van een eigenschap met de naam value naar het globale object.

Het kan handig zijn om een ​​functie te zien als geen kennis van de variabele waaraan deze is toegewezen. Dit helpt het idee versterken dat de waarde hiervan wordt gebonden wanneer de functie wordt aangeroepen in plaats van wanneer deze is gedefinieerd.


Einde van het extract.


71
2017-12-04 12:41



Het is soms handig als een object de functie van een ander object leent, wat betekent dat het leenobject eenvoudig de uitgeleende functie uitvoert alsof het zijn eigen functie was.

Een klein codevoorbeeld:

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

Deze methoden zijn erg handig om objecten tijdelijke functionaliteit te geven.


33
2018-02-25 19:31



Nog een voorbeeld met Call, Apply en Bind. Het verschil tussen bellen en toepassen is duidelijk, maar Binden werkt als volgt:

  1. Bind retourneert een exemplaar van een functie die kan worden uitgevoerd
  2. Eerste parameter is 'deze'
  3. Tweede parameter is a Kommagescheiden lijst met argumenten (zoals telefoontje)

}

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
*/

23
2018-03-31 07:32