Quelle est la différence entre call et apply?

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

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

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

y a-t-il des différences de rendement entre les deux méthodes susmentionnées? Quand est-il préférable d'utiliser call au lieu de apply et vice versa?

2781
demandé sur iridescent 2009-12-31 22:56:25
la source

20 ответов

la différence est que apply vous permet d'invoquer la fonction avec arguments comme un tableau; call exige que les paramètres soient énumérés explicitement. Utile mnémonique est " Un pour un rray et C pour c omma."

voir la documentation de MDN sur appliquer et appeler .

Pseudo syntaxe:

theFunction.apply(valueForThis, arrayOfArgs)

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

Il ya aussi, à partir de ES6, la possibilité de spread le tableau à utiliser avec la fonction call , vous pouvez voir les compatibilités ici .

code échantillon:

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
3347
répondu flatline 2017-12-19 19:10:20
la source

K. Scott Allen a un bel article intitulée sur la question.

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

la méthode apply() est identique à call(), sauf apply() nécessite un tableau comme second paramètre. Le tableau représente les arguments pour la méthode cible."

:

// assuming you have f
function f(message) { ... }
f.call(receiver, "test");
f.apply(receiver, ["test"]);
211
répondu notnoop 2012-07-20 00:53:50
la source

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 similaire (comme l'objet arguments pour transmettre vos propres arguments. Utilisez call autrement, 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 car je suis appelant la fonction. apply signifierait que vous êtes appliquant la fonction aux arguments (inexistants).

il ne devrait pas y avoir de différences de performances, sauf peut-être si vous utilisez apply et envelopper 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é, 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 ne déjà les arguments dans un tableau et apply est plus rapide si vous le faites.

151
répondu Matthew Crumley 2010-01-01 00:56:01
la source

Voici un bon mnémonique. Un ppliquez utilise Un rrays et Un oujours prend un ou deux Arguments. Lorsque vous utilisez c tout ce que vous avez à c dépasser le nombre d'arguments.

102
répondu Joe 2013-09-04 22:21:25
la source

bien que ce soit un vieux sujet, je voulais juste le souligner .appel est légèrement plus rapide que .appliquer. 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

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

.apply(this, [...])

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

91
répondu kmatheny 2014-01-18 21:44:50
la source

suit un extrait de fermeture: le guide définitif de Michael Bolin . Il peut paraître un peu longue, mais c'est saturé avec beaucoup de perspicacité. De "L'Annexe B. Souvent Mal Compris JavaScript Concepts":


Ce this se Réfère à Quand une Fonction est Appelée

Lorsqu'on appelle une fonction de la forme foo.bar.baz() , l'objet foo.bar est appelé récepteur. Lorsque la fonction est appelée, c'est le récepteur qui est utilisée 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 est pas explicite récepteur lorsqu'une fonction est appelée, l'objet global devient le récepteur. 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 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 renvoie à this , il est important de s'assurer que this aura la valeur correcte lorsqu'elle est appelée. 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.

parce que les fonctions sont de première classe objets en JavaScript, ils peuvent avoir leurs propres méthodes. Toutes les fonctions ont les méthodes call() et apply() qui permettent de redéfinir le récepteur (i.e., l'objet auquel this se réfère) lors de l'appel de la fonction. Les signatures de la 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;

noter que la seule différence entre call() et apply() est que call() reçoit les paramètres de fonction comme arguments individuels, tandis que apply() les reçoit comme 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, 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'utilise la valeur de son propre récepteur pour remplacer l'argument du récepteur lorsqu'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 peut ne jamais être null ou undefined quand une fonction est appelée. Lorsque null ou undefined est fourni comme récepteur à call() ou apply() , l'objet global est utilisé comme valeur pour 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é appelée value à l'objet global.

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


fin de l'extrait.

72
répondu Dominykas Mostauskis 2014-05-24 20:15:33
la source

il est parfois utile pour un objet d'emprunter la fonction d'un autre objet, ce qui signifie que l'objet d'emprunt exécute simplement la fonction de prêt comme s'il était le sien.

exemple de petit 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
répondu tjacks3 2014-02-25 23:31:51
la source

un autre exemple avec Call, Apply et Bind. La différence entre L'appel et L'application est évidente, mais Bind fonctionne comme ceci:

  1. Lier retourne une instance d'une fonction qui peut être exécutée
  2. le premier paramètre est ce
  3. Second paramètre est une virgule séparée 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
répondu Mahesh 2017-10-25 21:50:04
la source

j'aimerais vous 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
répondu 2014-01-16 16:47:13
la source

Call () prend les 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: http://blog.i-evaluation.com/2012/08/15/javascript-call-and-apply /

20
répondu Mark Karwowski 2014-01-25 20:40:32
la source

à Partir de le MDN docs sur la Fonction.prototype.appliquer() :

la méthode apply() appelle une fonction avec une valeur donnée this et les arguments fournis comme un tableau (ou un objet de type tableau).

syntaxe

fun.apply(thisArg, [argsArray])

à Partir de le MDN docs sur la Fonction.prototype.appel () :

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

syntaxe

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

À Partir De De La Fonction.appliquer et fonctionner.appelez JavaScript :

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


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 .

18
répondu John Slegers 2016-06-20 20:06:56
la source

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

11
répondu Rakesh Kumar 2014-02-28 08:57:48
la source

voici un petit post, je l'ai écrit sur ce:

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
répondu Dan 2013-12-04 17:58:29
la source

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

7
répondu Sanjib Debnath 2017-11-28 09:41:37
la source

nous pouvons différencier appel et appliquer des méthodes comme ci-dessous

appel: une fonction avec argument fournir individuellement. Si vous connaissez les arguments passés ou il n'y a aucun argument à passer, vous pouvez utiliser l'appel.

s'APPLIQUENT : Appel d'une fonction avec l'argument fourni comme un tableau. Vous pouvez utiliser apply si vous ne savez pas combien d'arguments vont passer à la fonction.

il y a un avantage à appliquer sur appel, nous ne besoin de changer le numéro de l'argument que nous pouvons modifier un tableau qui est passé.

il n'y a pas de grande différence dans la performance. Mais nous pouvons dire que l'appel est un peu plus rapide que Comparer pour appliquer parce qu'un tableau a besoin d'évaluer dans la méthode d'application.

6
répondu Praveen D 2013-11-06 15:50:46
la source

la différence entre ces méthodes sont, comment vous voulez passer les paramètres.

"pour Un tableau et C pour virgule" est une pratique mnémonique.

5
répondu venkat7668 2015-08-03 09:15:16
la source

appeler et appliquer les deux sont utilisés pour forcer la valeur this quand une fonction est exécutée. La seule différence est que call prend n+1 arguments où 1 est this et 'n' arguments . apply prend seulement deux arguments, l'un est this l'autre argument tableau.

l'avantage que je vois dans apply sur call est que nous pouvons facilement déléguer un appel de fonction à une autre fonction sans beaucoup 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 combien il est facile de déléguer hello à sayHello en utilisant apply , mais avec call c'est très difficile à réaliser.

5
répondu Raghavendra 2015-11-24 11:36:02
la source

Même si call et apply faites la même chose, je pense qu'il y a au moins un endroit où vous ne pouvez pas utiliser call , mais ne pouvez utiliser apply . C'est quand vous voulez soutenir l'héritage et souhaitez appeler le constructeur.

Voici une fonction qui vous permet de créer des classes qui supporte aussi 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
répondu Dhana Krishnasamy 2015-02-12 21:10:05
la source

la principale différence est, en utilisant call, que nous pouvons changer la portée et passer les arguments comme d'habitude, mais apply vous permet de l'appeler en utilisant les arguments comme un tableau (les passer comme 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 est presque identique à celle de appliquer(), la différence fondamentale est que call() accepte un argument liste, tout en s'appliquer() accepte un seul tableau d'arguments.

comme vous le voyez, il n'y a pas de 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 trouve le plus petit et le plus grand nombre dans un tableau de MDN, en utilisant 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)

donc la principale différence est juste la façon dont nous passons les arguments:



appel:

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

Appliquer:

function.apply(thisArg, [argsArray]);
3
répondu Alireza 2018-05-23 04:40:25
la source

résumé:

les méthodes call() et apply() sont situées sur Function.prototype . Ils sont donc disponibles sur chaque objet de fonction via la chaîne prototype. Les deux call() et apply() peuvent exécuter une fonction avec une valeur spécifiée du this .

La principale différence entre call() et apply() est la façon dont vous devez passer en arguments. À la fois call() et apply() vous passez comme premier argument l'objet que vous voulez être la valeur comme this . Les autres arguments diffèrent de la manière suivante:

  • Avec call() vous avez à mettre dans les arguments normalement (à partir de la deuxième argument)
  • avec apply() vous devez passer dans le tableau des 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 devrais-je utiliser ces fonctions?

la valeur this peut être délicate parfois en javascript. La valeur de this déterminée lorsqu'une fonction n'est pas exécutée lorsqu'une fonction est définie. si notre fonction dépend d'une liaison this , nous pouvons utiliser call() et apply() pour imposer 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
1
répondu Willem van der Veen 2018-08-29 18:29:42
la source

Autres questions sur javascript performance dynamic function