Question Quelle est la différence entre un appel et une demande?


Quelle est la différence entre utiliser call et apply invoquer une fonction?

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

func.apply(); contre func.call();

Existe-t-il des différences de performance entre les deux méthodes susmentionnées? Quand est-il préférable d'utiliser call plus de apply et vice versa?


2737
2017-12-31 19:56


origine


Réponses:


La différence est que apply vous permet d'invoquer la fonction avec arguments en tant que tableau; call nécessite que les paramètres soient listés explicitement. Un mnémonique utile est "UNE pour unerayer et C pour comma. "

Voir la documentation de MDN sur appliquer et appel.

Pseudo syntaxe:

theFunction.apply(valueForThis, arrayOfArgs)

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

Il y a aussi, à partir de ES6, la possibilité de spread le tableau pour une utilisation avec le call fonction, vous pouvez voir les compatibilités ici.

Exemple de code:

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 a une belle écriture à ce propos.

Fondamentalement, ils diffèrent sur la façon dont ils traitent les arguments de la fonction.

La méthode apply () est identique à call (), sauf que apply () nécessite un tableau en tant que deuxième paramètre. Le tableau représente les arguments de la méthode cible. "

Alors:

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

209
2017-12-31 19:59



Pour répondre à la partie sur le moment d'utiliser chaque fonction, utilisez apply si vous ne connaissez pas le nombre d'arguments que vous passerez, ou s'ils sont déjà dans un tableau ou un objet semblable à un tableau (comme le arguments objet pour transmettre vos propres arguments. Utilisation call sinon, puisqu'il n'y a pas besoin d'envelopper les arguments dans un tableau.

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

Quand je ne passe aucun argument (comme votre exemple), je préfère call depuis que je suis appel la fonction. apply impliquerait que vous êtes appliquer la fonction aux arguments (inexistants).

Il ne devrait y avoir aucune différence de performance, sauf peut-être si vous utilisez apply et enveloppez les arguments dans un tableau (par ex. f.apply(thisObject, [a, b, c]) au lieu de f.call(thisObject, a, b, c)). Je ne l'ai pas testé, donc il pourrait y avoir des différences, mais ce serait très spécifique au navigateur. Il est probable que call est plus rapide si vous n'avez pas déjà les arguments dans un tableau et apply est plus rapide si vous le faites.


150
2017-12-31 21:50



Voici un bon mnémonique. UNEutiliser pply UNErays et UNEIl faut toujours un ou deux arguments. Lorsque vous utilisez Ctout ce qu'il faut Count le nombre d'arguments.


102
2017-09-04 13:36



Bien que ce soit un vieux sujet, je voulais juste souligner que .call est légèrement plus rapide que .apply. Je ne peux pas vous dire exactement pourquoi.

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


[UPDATE!]

Douglas Crockford mentionne brièvement la différence entre les deux, ce qui peut aider à expliquer la différence de performance ... http://youtu.be/ya4UHuXNygM?t=15m52s

Appliquer prend un tableau d'arguments, tandis que Call prend zéro ou plusieurs paramètres individuels! Ah hah!

.apply(this, [...])

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


91
2017-11-07 17:36



Suit un extrait de Fermeture: Le Guide définitif de Michael Bolin. Cela peut sembler un peu long, mais il est saturé de beaucoup de perspicacité. De "Annexe B. Concepts JavaScript souvent mal compris":


Quelle this Fait référence à lorsqu'une fonction est appelée

Lors de l'appel d'une fonction du formulaire foo.bar.baz(), L'object foo.bar est appelé le récepteur. Lorsque la fonction est appelée, c'est le récepteur qui est utilisé comme valeur pour 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);

S'il n'y a pas de récepteur explicite lorsqu'une fonction est appelée, alors l'objet global devient le récepteur. Comme expliqué dans "goog.global" à la page 47, la fenêtre est l'objet global lorsque JavaScript est exécuté dans un navigateur Web. Cela conduit à un comportement surprenant:

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

Même si obj.addValues et f se référer à la même fonction, ils se comportent différemment lorsqu'ils sont appelés parce que la valeur du récepteur est différente dans chaque appel. Pour cette raison, lorsque vous appelez une fonction qui fait référence à this, il est important de s'assurer que this aura la bonne valeur quand il est appelé. Pour être clair, si this n'étaient pas référencés dans le corps de la fonction, alors le comportement de f(20) et obj.addValues(20) serait le même.

Les fonctions étant des objets de première classe dans JavaScript, elles peuvent avoir leurs propres méthodes. Toutes les fonctions ont les méthodes call() et apply() qui permettent de redéfinir le récepteur (c'est-à-dire, l'objet this fait référence à) lors de l'appel de la fonction. Les signatures de méthode sont les suivantes:

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

Notez que la seule différence entre call() et apply() est-ce call() reçoit les paramètres de la fonction en tant qu'arguments individuels, alors que apply() les reçoit en un seul tableau:

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

Les appels suivants sont équivalents, comme f et obj.addValues se référer à la même fonction:

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

Cependant, puisque ni call() ni apply() utilise la valeur de son propre récepteur pour substituer à l'argument récepteur quand il n'est pas spécifié, ce qui suit ne fonctionnera pas:

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

La valeur de this ne peut jamais être null ou undefined quand une fonction est appelée. Quand null ou undefined est fourni en tant que récepteur call() ou apply(), l'objet global est utilisé comme valeur pour le récepteur à la place. Par conséquent, le code précédent a le même effet secondaire indésirable d'ajouter une propriété nommée value à l'objet global.

Il peut être utile de considérer une fonction comme n'ayant aucune connaissance de la variable à laquelle elle est affectée. Cela contribue à renforcer l'idée que la valeur de ce sera lié lorsque la fonction est appelée plutôt que quand elle est définie.


Fin de l'extrait.


71
2017-12-04 12:41



Il est parfois utile pour un objet d'emprunter la fonction d'un autre objet, ce qui signifie que l'objet emprunteur exécute simplement la fonction prêt comme si elle était la sienne.

Un petit exemple de code:

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

Ces méthodes sont très utiles pour donner aux objets une fonctionnalité temporaire.


33
2018-02-25 19:31



Un autre exemple avec Call, Apply et Bind. La différence entre Call et Apply est évidente, mais Lier fonctionne comme ceci:

  1. Bind renvoie une instance d'une fonction pouvant être exécutée
  2. Le premier paramètre est 'ce'
  3. Le deuxième paramètre est un Séparées par des virgules liste d'arguments (comme Appel)

}

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



Je voudrais montrer un exemple, où l'argument 'valueForThis' est utilisé:

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] 

**détails: http://es5.github.io/#x15.4.4.7*


21
2017-07-05 10:56



Call () prend des arguments séparés par des virgules, ex:

.call(scope, arg1, arg2, arg3) 

et apply () prend un tableau d'arguments, ex:

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

Voici quelques exemples d'utilisation supplémentaires: http://blog.i-evaluation.com/2012/08/15/javascript-call-and-apply/


20
2018-01-21 18:11