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?
20 réponses
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
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"]);
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.
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.
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...)
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.
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.
un autre exemple avec Call, Apply et Bind. La différence entre L'appel et L'application est évidente, mais Bind fonctionne comme ceci:
- Lier retourne une instance d'une fonction qui peut être exécutée
- le premier paramètre est ce
- 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
*/
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 *
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 /
à 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 .
la différence fondamentale est que call()
accepte un liste d'arguments , tandis que apply()
accepte un tableau simple d'arguments .
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"
la différence est que call()
prend les arguments de fonction séparément, et apply()
prend les arguments de fonction dans un tableau.
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.
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.
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.
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
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]);
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