What is the difference between call and apply?

773,971

Solution 1

The difference is that apply lets you invoke the function with arguments as an array; call requires the parameters be listed explicitly. A useful mnemonic is "A for array and C for comma."

See MDN's documentation on apply and call.

Pseudo syntax:

theFunction.apply(valueForThis, arrayOfArgs)

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

There is also, as of ES6, the possibility to spread the array for use with the call function, you can see the compatibilities here.

Sample 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

Solution 2

K. Scott Allen has a nice writeup on the matter.

Basically, they differ on how they handle function arguments.

The apply() method is identical to call(), except apply() requires an array as the second parameter. The array represents the arguments for the target method."

So:

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

Solution 3

To answer the part about when to use each function, use apply if you don't know the number of arguments you will be passing, or if they are already in an array or array-like object (like the arguments object to forward your own arguments. Use call otherwise, since there's no need to wrap the arguments in an 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

When I'm not passing any arguments (like your example), I prefer call since I'm calling the function. apply would imply you are applying the function to the (non-existent) arguments.

There shouldn't be any performance differences, except maybe if you use apply and wrap the arguments in an array (e.g. f.apply(thisObject, [a, b, c]) instead of f.call(thisObject, a, b, c)). I haven't tested it, so there could be differences, but it would be very browser specific. It's likely that call is faster if you don't already have the arguments in an array and apply is faster if you do.

Solution 4

Here's a good mnemonic. Apply uses Arrays and Always takes one or two Arguments. When you use Call you have to Count the number of arguments.

Solution 5

While this is an old topic, I just wanted to point out that .call is slightly faster than .apply. I can't tell you exactly why.

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


[UPDATE!]

Douglas Crockford mentions briefly the difference between the two, which may help explain the performance difference... http://youtu.be/ya4UHuXNygM?t=15m52s

Apply takes an array of arguments, while Call takes zero or more individual parameters! Ah hah!

.apply(this, [...])

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

Share:
773,971
Noob
Author by

Noob

Currently a Ruby/Rails developer at Shopify, have also done javascript, Java and .Net programming in past lives.

Updated on July 08, 2022

Comments

  • Noob
    Noob almost 2 years

    What is the difference between using Function.prototype.apply() and Function.prototype.call() to invoke a function?

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

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

    Are there performance differences between the two aforementioned methods? When is it best to use call over apply and vice versa?

    • Larry Battle
      Larry Battle about 12 years
      Think of a in apply for array of args and c in call for columns of args.
    • Samih
      Samih over 10 years
      @LarryBattle I do almost the same, but I think a in apply for array and c in call for comma (i.e comma separated arguments).
    • Ringo
      Ringo over 10 years
      I agree it's stupid. What's annoying is that somehow this question gets asked during interviews because some influential chump added the question to their list of important js questions.
    • neaumusic
      neaumusic over 9 years
      the default "arguments" array that gets passed into a function's scope gets passed on with apply. arguments goes with array goes with apply, call accepts a manual list of models, not a collection object (array)
    • Gras Double
      Gras Double over 9 years
      You apply for a job once (one argument), you [phone] call people many times (several arguments). Alternative: there are [too?] many Call of Duty games.
    • Gras Double
      Gras Double over 9 years
      More classic, there's only one array, you apply it [as a whole], there're several arguments, you call them [in a row]. Take your pick :)
    • Gajus
      Gajus over 9 years
      When the intention is to invoke a variadic function with a list of argument values regardless of "this" value, then use the ES6 spread operator, e.g. fn(...input) where input is an array. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
    • DevWL
      DevWL over 8 years
      If you use "apply" or "call" only to chenge the "this" reference, and the function you refer to will not take any arguments, there is no diference what so ever.
    • Ankit Singh
      Ankit Singh over 7 years
      In ES6, if you've got an array of arguments args, only difference would be of three dots .... ie: fn.apply(context, args) or fn.call(context, ...args)
  • devios1
    devios1 about 13 years
    Are they both supported by the majority of browsers? I seem to remember reading that call() was more of an IE thing.
  • angry kiwi
    angry kiwi almost 13 years
    the second parameter of apply() and call() is optional, not required.
  • Eric Hodonsky
    Eric Hodonsky over 12 years
    This depends on what the function does with the parameters/array, if it doesn't need to process the array, does it take less time?
  • Josh Mc
    Josh Mc about 12 years
    Interestingly even without the array, call is still much faster. jsperf.com/applyvscallvsfn2
  • Kevin Schroeder
    Kevin Schroeder almost 12 years
    One thing to add is that the args must be a numerical array ([]). Associative arrays ({}) will not work.
  • Martijn
    Martijn over 11 years
    @KevinSchroeder: In javascript parlance, [] is called an array, {} is called an object.
  • Ikrom
    Ikrom about 11 years
    First parameter is not required too.
  • aziz punjani
    aziz punjani over 10 years
    I often used to forget which takes an array, and which expects you to list the arguments. A technique I used to remember it is if the first letter of the method starts with a then it takes an array i.e a pply array
  • Vincent McNabb
    Vincent McNabb over 10 years
    @JoshMc That would be very browser specific. In IE 11, I'm getting apply going twice as fast as call.
  • dantheta
    dantheta over 10 years
    Useful mnemonic right there!. I will change the 'one or two Arguments' to say 'a maximum of two Arguments' since neither the first or the second parameters of apply is required. I'm not sure though why one will call apply or call without a parameter. Looks like someone is trying to find out why here stackoverflow.com/questions/15903782/…
  • Raja
    Raja over 10 years
    1. Creating a new array means the garbage collector will need to clean it up at some point. 2. Accessing items in the array using dereference is less efficient than accessing a variable (parameter) directly. (I believe that is what kmatheny meant by "parsing", which is actually something quite different.) But neither of my arguments explain the jsperf. That must be related to the engine's implementation of the two functions, e.g. perhaps they create an empty array anyway, if none was passed.
  • Mark Karwowski
    Mark Karwowski over 10 years
    here is another one: blog.i-evaluation.com/2012/08/15/javascript-call-and-apply but basically it is right: .call(scope, arg1, arg2, arg3)
  • Michel Ayres
    Michel Ayres over 10 years
    To people that want to know how to see console.log check out: What is console.log and how do I use it?
  • Faraz Kelhini
    Faraz Kelhini over 10 years
  • some
    some almost 10 years
    @SAM Using call instead of a normal function call only makes sense if you need to change the value of this for the function call. An example (that convert a functions arguments-object to an array): Array.prototype.slice.call(arguments) or [].slice.call(arguments). apply makes sense if you have the arguments in an array, for example in a function that calls another function with (almost) the same parameters. Recommendation Use a normal function call funcname(arg1) if that does what you need, and save call and apply for those special occasions when you really need them.
  • Ralph Cowling
    Ralph Cowling over 9 years
    theFunction.call(undefined, ["Claude", "mathematician"]); // 'My name is Claude,mathematician and I am a undefined.' Oh Claude! <3 (photos-5.dropbox.com/t/1/…)
  • Kunal Singh
    Kunal Singh almost 9 years
    theFunction.apply(undefined, ["Susan", "school teacher"]); theFunction.call(undefined, "Claude", "mathematician"); Why the first argument is undefined while calling?
  • Kyll
    Kyll almost 9 years
    What does this answer provide that is not already well-provided in other answers?
  • Viktor Stolbin
    Viktor Stolbin over 8 years
    Just to note the fact, that additionalValues is not referenced inside obj.addValues body
  • A J Qarshi
    A J Qarshi over 8 years
    @KunalSingh Both call and apply takes two parameters. The first argument of apply' and call` function must be the owner object and the second parameter will be array or comma separated parameters respectively. If you pass null or undefined as first argument then in non-strict mode they are replaced with global object i.e. window
  • xgqfrms
    xgqfrms over 7 years
    # codes bugs theFunction.apply(undefined, ...["Matthew", "physicist"]); A_better_apply
  • xgqfrms
    xgqfrms over 7 years
    ` // call() === comma-separated arguments (arguments-list) .call(this, args1, args2, args3, ...) // apply() === array of arguments (array-items) .apply(this, [arr0, arr1, arr2, ...]) `
  • Álvaro González
    Álvaro González about 7 years
    The mnemonic alone is worth the answer. I don't think I'll need to look it up again!
  • Gary
    Gary almost 7 years
    Thank you for sharing the test and video
  • jhliberty
    jhliberty over 6 years
    I believe call would work there with the spread operator as described in the selected answer. Unless I'm missing something.
  • jhliberty
    jhliberty over 6 years
    I know you were answering the question but would like to add: you could have used bind when defining f. var f = obj.addValues; becomes var f = obj.addValues.bind(obj) and now f(20) would work without having to use call or apply every time.
  • candy_man
    candy_man over 6 years
    @AJQarshi @KunalSingh Just to expound on Qarshi's answer, the first argument, owner object, as he called it, is the execution context you want to pass to the function(this context). When an object is passed as argument, then the function invoked is bound to the object's execution context and any reference to members in the function will indeed point to existing object members. Hope this makes sense.
  • iamcastelli
    iamcastelli over 4 years
    @Ikrom, the first parameter is not required for call but a requirement for apply
  • Fralcon
    Fralcon over 4 years
    I know you didn't write it, but you did highlight the text and examples from the book as relevant, and I am very grateful. They were very helpful.
  • Jakub Kubista
    Jakub Kubista about 4 years
    You can hear this in every second interview, but I've seen this like once-twice in practice since most of the junior devs don't know this so it would lead just to misunderstandings.
  • Vega
    Vega about 4 years
    Although we appreciate the effort you did making images, they are not very useful. Nobody can copy the code to use, test, improve... The code should be pasted as text here