Function.apply and Function.call in JavaScript

In order to explain how the createDelegate function works in the last post, we have to understand JavaScript closures and Function.apply(). The apply() method is the easiest subject to tackle, so we'll start there and work up.

Every function in JavaScript has a number of attached methods, including toString(), call(), and apply(). If it sounds odd to you that a function might have its own methods - then remember that every function in JavaScript is an object. Read this article for a refresher. You might also wonder what the difference is between a function and a method. I believe the descriptors 'function' and 'method' are just a JavaScript convention. Functions stand on their own (there is an alert() function, for example), while methods are functions inside an object's dictionary, and we invoke them through the object reference. Every JavaScript object has a toString() method, for example, and we can use the toString() method on a function object to see its source code:

function foo()
{
    alert(
'x');
}

alert(foo.toString());

Because functions are objects they can have their own properties and methods, and we can treat them like data. "Functions as data" is important to remember for the next post, too, but for now we'll focus on two of a function's methods: apply(), and its counterpart: call().

Let's start with the following code:

var x = 10;

function f()
{
    alert(
this.x);
}

f();

Here we have a global function by the name of f(). f() uses the this keyword to reference x, but notice we don't invoke the function through an instance of an object. So what object does this reference? this will reference the global object. The global object is where we defined the variable x. The above code does work and will show the value 10 in a dialog.

Both call() and alert() are methods we can use to assign the this pointer for the duration of a method invocation. As an example, here is how we could use the call() method:

var x = 10;
var o = { x: 15 };

function f()
{
    alert(
this.x);
}

f();
f.call(o);

The first invocation of f() will display the value of 10, because this references the global object. The second invocation (via the call method) however, will display the value 15. 15 is the value of the x property inside object o. The call() method invokes the function and uses its first parameter as the this pointer inside the body of the function. In other words - we've told the runtime what object to reference as this while executing inside of function f().

Fiddling with the this pointer might sound funny, even perverse, to C++, Java, and C# programmers. What's next? Dogs sleeping with cats? Working nVidia drivers for Windows Vista? It's all part of the fun that is ECMAScript.

We can also pass arguments to the target function via call():

var x = 10;
var o = { x: 15 };
function f(message)
{
    alert(message);
    alert(
this.x);
}

f(
"invoking f");
f.call(o,
"invoking f via call");

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.

var x = 10;
var o = { x: 15 };
function f(message)
{
    alert(message);
    alert(
this.x);
}

f(
"invoking f");
f.apply(o, [
"invoking f through apply"]);

The apply() method is useful because we can build a function like createDelegate (from the last post) that doesn't care about the signature of the target method. The function can use apply() to pass all additional arguments to the target method via an array. Are we getting close to a curry function?

var o = { x: 15 };

function f1(message1)
{
    alert(message1 +
this.x);
}

function f2(message1, message2)
{
    alert(message1 + (
this.x * this.x) + message2);
}

function g(object, func, args)
{
    func.apply(object, args);
}

g(o, f1, [
"the value of x = "]);
g(o, f2, [
"the value of x squared = ", ". Wow!"]);

The problem here is the awkward syntax. We are forcing the caller to stuff arguments into an array just so we call apply(). Fortunately, there is a way to make the syntax easier, but we have to introduce one more topic: the arguments identifier.

In JavaScript, every function essentially has a variable length argument list. The means we can pass 5 parameters to a function even if the function only uses one argument. The following runs without error and displays "H":

function f(message)
{
    alert(message);
}

f(
"H", "e", "l", "l", "o");

If we did want to access the other arguments from inside f(), we can use the arguments keyword. arguments references an Arguments object, which has a length property and feels like an array.

function f(message)
{
    
// message param is the same as arguments[0]    
  
    
for(var i = 1; i < arguments.length; i++)
    {
        message += arguments[i];
    }
    
    alert(message);
}

// this will say "Hello"
f("H", "e", "l", "l", "o");

Just so you know, arguments is technically not an array, even if it walks and talks like one. arguments has a length property but no split, push, or pop methods. What we can do with arguments inside our previous g() function is copy the incoming arguments after arguments[1] into an array object that we pass to apply.

var o = { x: 15 };

function f(message1, message2)
{
    alert(message1 + (
this.x * this.x) + message2);
}

function g(object, func)
{          
    
// arguments[0] == object
    // arguments[1] == func
    
    
    
var args = []; // empty array
    // copy all other arguments we want to "pass through"
    for(var i = 2; i < arguments.length; i++)
    {
        args.push(arguments[i]);
    }

    func.apply(object, args);
}

g(o, f,
"The value of x squared = ", ". Wow!");

When we invoke g(), we can pass additional arguments as parameters instead of stuffing the arguments into an array.

At this point, we have the theoretical knowledge needed to understand call and apply, but perhaps you are already asking a question: what if I don't want to immediately invoke the target function f()? What if I just want to arrange all the players in this little drama so that I can invoke f() at some later point (as an event handler, for example), but still have this referencing the desired object (whithout tracking the desired object myself). In an upcoming post, we'll see how to combine our Function.apply and arguments knowledge with the concept of nested functions and closures to answer this very question.

Print | posted @ Thursday, July 05, 2007 1:12 AM

Comments on this entry:

Gravatar # re: Function.apply and Function.call in JavaScript
by Laimis at 7/5/2007 3:07 PM

OK, this is a great series of articles. Keep them going!
  
Gravatar # re: Function.apply and Function.call in JavaScript
by Sebastian at 7/9/2007 5:32 PM

Great post. I was implementing events for my own javascript objects and this helped a lot when implementing the triggers because the triggers should perform actions that only will know the arguments (when they have) at trigger time.
Thank you for your didactism.
Cheers,
Sebastian
  
Gravatar # re: Function.apply and Function.call in JavaScript
by Aamir Afridi at 11/17/2009 6:34 AM

Really great article. I just learn alot of new stuff. Keep it going.
  
Gravatar # re: Function.apply and Function.call in JavaScript
by K at 1/23/2010 10:27 PM

awesome post!
  
Gravatar # re: Function.apply and Function.call in JavaScript
by K at 1/23/2010 10:27 PM

awesome post!
  
Gravatar # re: Function.apply and Function.call in JavaScript
by seb at 2/14/2010 6:31 PM

Best damn written explanation Ive seen in a long time. Thanks
  
Gravatar # re: Function.apply and Function.call in JavaScript
by Gerrat at 4/9/2010 10:07 AM

Awesome article!
  
Gravatar # re: Function.apply and Function.call in JavaScript
by Takloo at 4/30/2010 5:16 AM

This was a very clear explanation. Thank you.
  
Gravatar # re: Function.apply and Function.call in JavaScript
by igor at 6/14/2010 6:42 PM

Great explanation! All is clear now! Thanx!
  
Gravatar # re: Function.apply and Function.call in JavaScript
by Jags at 8/6/2010 12:24 PM

Nice article. Thank you.
  
Gravatar # re: Function.apply and Function.call in JavaScript
by Tim Farland at 8/16/2010 10:57 AM

Thanks! I was really having trouble getting my head around call/apply, but it clicked when you explained it with: 'we've told the runtime what object to reference as *this* while executing inside of function f().'
  
Gravatar # re: Function.apply and Function.call in JavaScript
by Carlos at 11/27/2010 6:14 AM

Great article!!

I have readed a lot about "call()" and "apply()", but i didn't understand how they worked, and finally thanks to this.article i understand it now!! :)
  
Gravatar # re: Function.apply and Function.call in JavaScript
by Tom at 12/1/2010 1:53 PM

Very informative article (and answers a problem I has as well). Thanks!
  
Gravatar # re: Function.apply and Function.call in JavaScript
by Selva at 12/6/2010 6:19 AM

Nice Article
  
Gravatar # re: Function.apply and Function.call in JavaScript
by HKansal at 12/24/2010 4:20 PM

ummm.. I seemed to be a bit confused here.
Why do we actually need call() and apply() methods and tell them which object to call our function on? Why can't we straight away call that function on our object?
  
Gravatar # re: Function.apply and Function.call in JavaScript
by scott at 12/26/2010 10:48 AM

It's a layer of indirection. The previous post about createDelegate might help. We don't want to call the function directly, we want to create something that will allow us to call the function at a later time, and with the proper arguments saved.
  
Gravatar # re: Function.apply and Function.call in JavaScript
by Mark at 2/6/2011 4:59 PM

Hey, great article. Much appreciate. If think you should add a "donate" button somewhere.
  
Gravatar # re: Function.apply and Function.call in JavaScript
by JJ at 2/16/2011 10:37 AM

Good article. In the last example, couldn't you just do:

func.apply(object, Array().slice.call(arguments, 2));

or

func.apply(object, Array.prototype.slice.call(arguments, 2));

This would eliminated the for() loop.
  
Gravatar # re: Function.apply and Function.call in JavaScript
by scott at 2/16/2011 2:16 PM

@JJ - yes, thank you! I still had a lot to learn when I wrote that article (and today, too).
  
Gravatar # re: Function.apply and Function.call in JavaScript
by Parag Shah at 3/6/2011 2:05 AM

Thanks for the wonderful explanation. I was having a hard time trying to understand call and apply. Reading your blog post helped me understand them much better.
  
Comments have been closed on this topic.
Scott Allen
Posts - 869
Comments - 4493
Stories - 14