Domanda Qual è la differenza tra call e apply?


Qual è la differenza tra l'utilizzo call e apply invocare una funzione?

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

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

Ci sono differenze di prestazioni tra i due metodi sopra menzionati? Quando è meglio usare call al di sopra di apply e viceversa?


2737
2017-12-31 19:56


origine


risposte:


La differenza è questa apply ti permette di invocare la funzione con arguments come una matrice; call richiede che i parametri siano elencati esplicitamente. Un utile mnemonico è "UN per unrray e C per cOMMA."

Vedi la documentazione di MDN su applicare e chiamata.

Pseudo sintassi:

theFunction.apply(valueForThis, arrayOfArgs)

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

C'è anche, a partire da ES6, la possibilità di spread la matrice da usare con call funzione, puoi vedere le compatibilità Qui.

Codice d'esempio:

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 ha una bella recensione in merito.

Fondamentalmente, differiscono su come gestiscono gli argomenti delle funzioni.

Il metodo apply () è identico a call (), ad eccezione di apply () richiede un array come secondo parametro. La matrice rappresenta gli argomenti per il metodo di destinazione. "

Così:

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

209
2017-12-31 19:59



Per rispondere alla parte su quando utilizzare ciascuna funzione, utilizzare apply se non conosci il numero di argomenti che stai passando, o se sono già in un array o in un oggetto simile a un array (come il arguments oggetto di inoltrare i propri argomenti. Uso call altrimenti, poiché non è necessario avvolgere gli argomenti in un array.

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

Quando non sto passando nessun argomento (come il tuo esempio), preferisco call da quando sono chiamata la funzione. apply implicherebbe che tu sia l'applicazione la funzione agli argomenti (inesistenti).

Non ci dovrebbero essere differenze di prestazioni, tranne forse se si utilizza apply e avvolgere gli argomenti in una matrice (ad es. f.apply(thisObject, [a, b, c]) invece di f.call(thisObject, a, b, c)). Non l'ho testato, quindi potrebbero esserci differenze, ma sarebbe molto specifico per il browser. È probabile che call è più veloce se non hai già gli argomenti in un array e apply è più veloce se lo fai.


151
2017-12-31 21:50



Ecco un buon mnemonico. UNusi pply UNrrays e UNsempre prende uno o due argomenti. Quando usi Ctutto ciò che devi Cprendi il numero di argomenti.


102
2017-09-04 13:36



Mentre questo è un vecchio argomento, volevo solo sottolineare che. Call è leggermente più veloce di .apply. Non posso dirti esattamente perché.

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


[UPDATE!]

Douglas Crockford menziona brevemente la differenza tra i due, che può aiutare a spiegare la differenza di prestazioni ... http://youtu.be/ya4UHuXNygM?t=15m52s

Apply accetta una serie di argomenti, mentre Call prende zero o più parametri individuali! Ah ah!

.apply(this, [...])

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


91
2017-11-07 17:36



Segue un estratto da Chiusura: la guida definitiva di Michael Bolin. Potrebbe sembrare un po 'lungo, ma è saturo di molte intuizioni. Da "Appendice B. Concetti JavaScript frequentemente fraintesi":


Che cosa this Si riferisce a Quando viene chiamata una funzione

Quando si chiama una funzione del modulo foo.bar.baz(), l'oggetto foo.bar è indicato come il ricevitore. Quando viene chiamata la funzione, è il ricevitore utilizzato come valore per 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);

Se non è presente un destinatario esplicito quando viene chiamata una funzione, l'oggetto globale diventa il destinatario. Come spiegato in "goog.global" a pagina 47, window è l'oggetto globale quando JavaScript viene eseguito in un browser web. Ciò porta ad alcuni comportamenti sorprendenti:

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

Nonostante obj.addValues e f si riferiscono alla stessa funzione, si comportano diversamente quando vengono chiamati perché il valore del ricevitore è diverso in ogni chiamata. Per questo motivo, quando si chiama una funzione a cui si fa riferimento this, è importante assicurarlo this avrà il valore corretto quando viene chiamato. Per essere chiari, se this non erano referenziati nel corpo della funzione, quindi il comportamento di f(20) e obj.addValues(20) sarebbe lo stesso

Poiché le funzioni sono oggetti di prima classe in JavaScript, possono avere i propri metodi. Tutte le funzioni hanno i metodi call() e apply() che rendono possibile ridefinire il ricevitore (ad esempio, l'oggetto this si riferisce a) quando si chiama la funzione. Le firme del metodo sono le seguenti:

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

Si noti che l'unica differenza tra call() e apply() è questo call() riceve i parametri della funzione come argomenti individuali, mentre apply() li riceve come un singolo 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]);

Le seguenti chiamate sono equivalenti, come f e obj.addValues fare riferimento alla stessa funzione:

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

Tuttavia, poiché nessuno dei due call() né apply() utilizza il valore del proprio ricevitore per sostituire l'argomento ricevitore quando non è specificato, il seguente non funzionerà:

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

Il valore di this non può mai essere null o undefined quando viene chiamata una funzione. quando null o undefined è fornito come ricevitore a call() o apply(), l'oggetto globale viene invece utilizzato come valore per il ricevitore. Pertanto, il codice precedente ha lo stesso effetto collaterale indesiderato dell'aggiunta di una proprietà denominata value all'oggetto globale.

Può essere utile pensare a una funzione come se non avesse conoscenza della variabile a cui è assegnata. Ciò aiuta a rafforzare l'idea che il valore di questo sarà associato quando viene chiamata la funzione piuttosto che quando è definita.


Fine dell'estratto


71
2017-12-04 12:41



A volte è utile che un oggetto prenda in prestito la funzione di un altro oggetto, il che significa che l'oggetto in prestito esegue semplicemente la funzione prestata come se fosse propria.

Un piccolo esempio di codice:

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

Questi metodi sono molto utili per dare agli oggetti funzionalità temporanee.


33
2018-02-25 19:31



Un altro esempio con Call, Apply e Bind. La differenza tra Call e Apply è evidente, ma legare funziona in questo modo:

  1. Bind restituisce un'istanza di una funzione che può essere eseguita
  2. Il primo parametro è 'Questo'
  3. Il secondo parametro è a Separato da virgola lista di argomenti (come Chiamata)

}

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



Mi piacerebbe mostrare un esempio, in cui viene utilizzato l'argomento 'valueForThis':

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] 

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


21
2017-07-05 10:56