web-dev-qa-db-fra.com

Quelle est la difference entre call et apply?

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

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

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

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

2974
John Duff

La différence est que apply vous permet d'appeler la fonction avec arguments sous forme de tableau; call nécessite que les paramètres soient listés explicitement. Un mnémonique utile est "A pour a rray et C pour c omma. "

Voir la documentation de MDN sur apply et call .

Pseudo syntaxe:

theFunction.apply(valueForThis, arrayOfArgs)

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

Il existe également, à partir de ES6, la possibilité de spread le tableau à utiliser avec la fonction call, 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
3519
flatline

K. Scott Allen a n bel écrit en la matière.

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

La méthode apply () est identique à call (), sauf que apply () nécessite un tableau en tant que second 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"]);
220
notnoop

Pour répondre à la question de savoir quand utiliser chaque fonction, utilisez apply si vous ne connaissez pas le nombre d'arguments que vous allez transmettre, ou s'ils se trouvent déjà dans un tableau ou un objet semblable à un tableau (comme le arguments objet pour transférer vos propres arguments, utilisez call sinon, puisqu'il n'est pas nécessaire de placer 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 puisque je appelle la fonction. apply signifierait que vous appliquez la fonction aux arguments (non existants).

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

153
Matthew Crumley

Voici un bon mnémonique. UNEutilisations ppl UNErays et UNEprend toujours un ou deux arguments. Quand vous utilisez Ctout ce que vous devez Cmontez le nombre d'arguments.

106
Joe

Bien qu’il s’agisse d’un sujet ancien, je tenais simplement à 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/


[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

Apply prend un tableau d'arguments, tandis que Call ne prend aucun ou plusieurs paramètres individuels! Ah ah!

.apply(this, [...])

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

91
kmatheny

Suit un extrait de Closure: The Definitive Guide de Michael Bolin . Cela peut sembler un peu long, mais il est saturé de perspicacité. Dans "Annexe B. Concepts JavaScript souvent mal compris":


À quoi this fait-on référence quand une fonction est appelée

Lors de l'appel d'une fonction de la forme foo.bar.baz(), l'objet foo.bar est appelé le destinataire. 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 destinataire explicite lorsqu'une fonction est appelée, l'objet global devient le destinataire. Comme expliqué dans "goog.global" à la page 47, window 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 font référence à la même fonction, ils se comportent différemment à l'appel, car la valeur du destinataire est différente dans chaque appel. Pour cette raison, lorsque vous appelez une fonction faisant référence à this, il est important de vous assurer que this aura la bonne valeur lors de son appel. Pour être clair, si this n'était pas référencé dans le corps de la fonction, le comportement de f(20) et obj.addValues(20) serait alors le même.

Comme les fonctions sont des objets de première classe en 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 auquel 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 que call() reçoit les paramètres de la fonction sous forme d'arguments individuels, alors que apply() les reçoit sous la forme d'un tableau unique:

// 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, car f et obj.addValues font référence à la même fonction:

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

Cependant, étant donné que ni call() ni apply() n'utilisent la valeur de son propre récepteur pour remplacer l'argument du destinataire lorsqu'il n'est pas spécifié, les opérations suivantes ne fonctionneront 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 ni undefined quand une fonction est appelée. Lorsque null ou undefined est fourni en tant que récepteur à call() ou apply(), l'objet global est utilisé comme valeur pour le récepteur. 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 penser qu’une fonction n’a aucune connaissance de la variable à laquelle elle est affectée. Cela contribue à renforcer l’idée que la valeur de celle-ci sera liée lors de l’appel de la fonction plutôt que lors de sa définition.


Fin de l'extrait.

75

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

n 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
tjacks3

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

  1. Bind renvoie une instance d'une fonction pouvant être exécutée
  2. Le premier paramètre est ' this '
  3. Le second paramètre est une liste d'arguments ( séparés par des virgules ) (comme Call ).

}

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

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 *

23
user669677

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
Mark Karwowski

Depuis , les documents MDN de Function.prototype.apply () :

La méthode apply () appelle une fonction avec une valeur this donnée et des arguments fournis sous forme de tableau (ou d'objet semblable à un tableau).

Syntaxe

fun.apply(thisArg, [argsArray])

Depuis , les documents MDN sur Function.prototype.call () :

La méthode call () appelle une fonction avec une valeur this donnée et des arguments fournis individuellement.

Syntaxe

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

De Function.apply et Function.call en JavaScript :

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


Exemple de code:

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

Voir aussi ce violon .

19
John Slegers

La différence fondamentale est que call() accepte une liste d'arguments , tandis que apply() accepte un tableau unique d'arguments .

11
Rakesh Kumar

Voici un petit article, j'ai écrit à ce sujet:

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

La différence est que call() prend les arguments de la fonction séparément et apply() prend les arguments de la fonction dans un tableau.

7
Sanjib Debnath

Nous pouvons différencier les méthodes d'appel et d'application comme ci-dessous

CALL: Une fonction avec argument fournit individuellement. Si vous connaissez les arguments à transmettre ou s'il n'y en a pas, vous pouvez utiliser call.

APPLY: Appelle une fonction avec un argument fourni sous forme de tableau. Vous pouvez utiliser apply si vous ne savez pas combien d'arguments vont être passés à la fonction.

Il y a un avantage à utiliser apply sur call, nous n'avons pas besoin de changer le nombre d'arguments, mais nous pouvons aussi changer un tableau passé.

Il n'y a pas grande différence de performance. Mais nous pouvons dire que call est un peu plus rapide que comparé à appliquer car un tableau doit être évalué dans la méthode apply.

6
Praveen D

Appelez et appliquez les deux pour forcer la valeur this lorsqu'une fonction est exécutée. La seule différence est que call prend n+1 arguments où 1 représente this et 'n' arguments. apply ne prend que deux arguments, l'un est this l'autre est un tableau d'arguments.

L'avantage que je vois dans apply par rapport à call est que nous pouvons facilement déléguer un appel de fonction à une autre fonction sans trop d'effort;

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

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

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

Observez la facilité avec laquelle nous avons délégué hello à sayHello en utilisant apply, mais avec call cela est très difficile à obtenir.

5
Raghavendra

La différence entre ces méthodes est la façon dont vous voulez transmettre les paramètres.

"A pour tableau et C pour virgule" est un mnémonique pratique.

5
venkat7668

Même si call et apply réalisent la même chose, je pense qu’il existe au moins un endroit où vous ne pouvez pas utiliser call mais vous ne pouvez utiliser que apply. C'est à ce moment que vous souhaitez prendre en charge l'héritage et que vous souhaitez appeler le constructeur.

Voici une fonction qui vous permet de créer des classes qui prend également en charge la création de classes en étendant d’autres classes.

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
Dhana Krishnasamy

La principale différence est que, en utilisant call, nous pouvons modifier la portée et transmettre les arguments normalement, mais appliquer vous permet de l'appeler en utilisant des arguments sous forme de tableau (les transmettre sous forme de tableau). Mais en ce qui concerne ce qu'ils doivent faire dans votre code, ils sont assez similaires.

Bien que la syntaxe de cette fonction soit presque identique à celle de apply (), la différence fondamentale est que call () accepte une liste d'arguments, tandis que apply () accepte un seul tableau d'arguments.

Donc, comme vous le voyez, il n'y a pas une grande différence, mais il y a quand même des cas où nous préférons utiliser call () ou apply (). Par exemple, regardez le code ci-dessous, qui recherche le nombre le plus petit et le plus grand dans un tableau à partir de MDN, à l'aide de la méthode apply:

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

La différence principale réside donc dans la manière dont nous passons les arguments:

Call:

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

Appliquer:

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

Sommaire:

call() et apply() sont des méthodes qui se trouvent sur Function.prototype. Par conséquent, ils sont disponibles sur chaque objet de fonction via la chaîne de prototypes. call() et apply() peuvent tous deux exécuter une fonction avec une valeur spécifiée de this.

La principale différence entre call() et apply() est que vous devez y passer des arguments. Dans call() et apply(), vous transmettez comme premier argument l'objet que vous souhaitez utiliser comme valeur this. Les autres arguments diffèrent de la manière suivante:

  • Avec call() vous devez entrer les arguments normalement (à partir du second argument)
  • Avec apply() vous devez transmettre un tableau d'arguments.

Exemple:

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

Pourquoi aurais-je besoin d'utiliser ces fonctions?

La valeur this peut être délicate parfois en javascript. La valeur de this déterminée lorsqu'une fonction est exécutée, pas lorsqu'une fonction est définie. Si notre fonction dépend d'un lien droit this, nous pouvons utiliser call(). et apply() pour appliquer ce comportement. Par exemple:

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
Willem van der Veen