Changing The Execution Context Of JavaScript Functions Using Call() And Apply()
Yesterday, as I writing about changing the execution context of self-executing functions in JavaScript, I realized that I didn't have a good general post on what execution context was or how it can be changed. I've talked about it a number of times, but never in a really cohesive way. In JavaScript, all function bodies have access to the "this" keyword. The "this" keyword is the context of the function execution. By default, "this" is a reference to the object on which a particular function is called (in JavaScript all functions are bound to an object). We can, however, use call() and apply() to change this binding at runtime.
First, let's clarify the fact that all functions in JavaScript are actually "methods." That is, they are all properties of some object. We can define functions that appear to be free-floating; however, these free-floating functions are implicitly created as properties of the global scope (ie. the Window object in the web browser). This means that functions defined without an explicit context can be accessed as a window property:
// Define the free-floating function.
function someMethod(){ ... }
// Access it as a property of Window.
window.someMethod();
Now that we understand that all functions in JavaScript are properties of an object, we can talk about the default binding of the execution context. By default, a JavaScript function is executed in the context of the object for which it is a property. That is, within the function body, the "this" keyword is a reference to the parent object. As such, in the following code:
sarah.sayHello();
... the "this" keyword within the sayHello() method is a reference to the sarah object.
Similarly, in this code:
getScreenResolution();
... the "this" keyword within the getScreenResolution() function is a reference to the window object (since unbound functions are implicitly bound to the global scope).
If we want to, we can dynamically change the execution context of any method by using either call() or apply(). Both of these functions can be used to bind the "this" keyword to an explicit context. While similar in outcome, these two functions differ in their method signature:
method.call( newThisContext, Param1, ..., Param N )
method.apply( newThisContext, [ Param1, ..., Param N ] );
As you can see, call() takes a new context binding and N inline arguments. apply(), on the other hand, takes a new context binding and then an array of N arguments. The difference here is simply how the arguments get passed to the method in question. In both cases, the "this" keyword of the function body will refer to the newThisContext object provided during invocation.
Let's explore this concept with some code. In the following demo, we've got a few objects and a function. We're going to use call() and apply() to dynamically change the execution context of the given function at runtime, regardless of where the function happens to live.
<!DOCTYPE html>
<html>
<head>
<title>Changing Execution Context In JavaScript</title>
<script type="text/javascript">
// Create a global variable for context (this lives in the
// global scope - window).
var context = "Global (ie. window)";
// Create an object.
var objectA = {
context: "Object A"
};
// Create another object.
var objectB = {
context: "Object B"
};
// -------------------------------------------------- //
// -------------------------------------------------- //
// Define a function that uses an argument AND a reference
// to this THIS scope. We will be invoking this function
// using a variety of approaches.
function testContext( approach ){
console.log( approach, "==> THIS ==>", this.context );
}
// -------------------------------------------------- //
// -------------------------------------------------- //
// Invoke the unbound method with standard invocation.
testContext( "testContext()" );
// Invoke it in the context of Object A using call().
testContext.call(
objectA,
".call( objectA )"
);
// Invoke it in the context of Object B using apply().
testContext.apply(
objectB,
[ ".apply( objectB )" ]
);
// -------------------------------------------------- //
// -------------------------------------------------- //
// Now, let's set the test method as an actual property
// of the object A.
objectA.testContext = testContext;
// -------------------------------------------------- //
// -------------------------------------------------- //
// Invoke it as a property of object A.
objectA.testContext( "objectA.testContext()" );
// Invoke it in the context of Object B using call.
objectA.testContext.call(
objectB,
"objectA.testContext.call( objectB )"
);
// Invoke it in the context of Window using apply.
objectA.testContext.apply(
window,
[ "objectA.testContext.apply( window )" ]
);
</script>
</head>
<body>
<!-- Left intentionally blank. -->
</body>
</html>
As you can see, we have a property, context, defined on window, objectA, and objectB. We then use call() and apply() to execute the testContext() method in the context of the above objects. Doing so results in the following console output:
testContext() ==> THIS ==> Global (ie. window)
.call( objectA ) ==> THIS ==> Object A
.apply( objectB ) ==> THIS ==> Object B
objectA.testContext() ==> THIS ==> Object A
objectA.testContext.call( objectB ) ==> THIS ==> Object B
objectA.testContext.apply( window ) ==> THIS ==> Global (ie. window)
As you can see, the "this" keyword within the function body is bound to the first argument of either the call() or apply() functions. This is true regardless of where the invoked method resides.
.... hmmm, not sure how to end this. I'm feeling like this blog post wasn't very well articulated. I wrote, however, so I might as well post it.
Want to use code from this post? Check out the license.
Reader Comments
Articulated perfectly for me. This is one of those concepts thrown around quite a bit at the jqcon sessions that I knew I needed to understand, and *sort of* did, but this post really gelled it together for me.
So thanks.
I guess my next gray area would be when/why to use call() vs. apply(). If I figure that out I'll report back.
This is the most sense
and
ever made. Great post!
Ok cool - maybe it made more sense than I realized :)
@Wilkins,
Sorry about the inline Code block. That's something I've been meaning to fix for a while.
@Ben, oh yeah, that. I wasn't expecting that. Ah well. :P
Very helpful, the part I do not quite understand is this one :
// Now, let's set the test method as an actual property
// of the object A.
objectA.testContext = testContext;
Why do this and what does happen. It seem to have no effect.
This is an interesting concept to me. Made sense just not really able to picture what I would use this for yet.
@Jean-Philippe,
In that step, we're simply copying a function pointer from one container into another. This code:
... could be re-rewritten as:
We're basically just making testContext() a property of *both* the window object and the objectA. Doing this will dynamically bind the "this" reference during the method invocation. So, once this copy has been made, calling:
window.testContext()
... will cause "this" to be bound to window. And calling this:
objectA.testContext()
... will cause "this" to be bound to objectA.
The "this" keyword references the "container" object by default. Then, we can further use call() and apply() to change it explicitly.
@Dustin,
It starts to get more exciting when you get into event binding in libraries like jQuery where you need to invoke a given callback (ie. a function), in a particular context.
... but that's a bit too abstract to really get much out of without seeing some code.
@Ben,
.call reveals so much about JS. Every function has it defined, but .call itself is a function. So that means .call.call is defined. And .call.call.call. It's not just theoretical. I've tried it. It's true in all browsers.
What does this mean? It means the .call doesn't actually exist until you call it into existence by referencing it. (That seems like it might be a pun, but I don't think so.)
It HAS to mean that though. Otherwise, the first function you define would result in an infinite loop in the interpreter, as it kept defining more and more .call methods of .call methods.
And all JS functions are "higher level functions", capable of accepting functions as arguments and returning functions as results (as in currying). That means that, if func returns a function, func.call(...).call exists too. But only when you call it.
This stuff makes me feel like John Forbes Nash when he used to let his mind get caught in tight loops of numerological analysis of friends' social security numbers.
I've only recently discovered:
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind
it can be used to bind a function to a certain context (obj parameter), so when you call the function it always executes in that context.
@WebManWalking
I've never thought about .call.call before. I tried it after reading your comment. I believe however that it is actually a circular reference and not that it doesn't exist until you call it. All objects in JS are passed by reference and functions are objects. Consider:
As in .call.call, foo.foo just points back to itself.
@Ben
I really enjoyed your previous post on changing the this context of self executing function blocks. I've not considered that before. Very interesting stuff. Thanks for that and many other gems here on your blog.
In most cases I find I need to get a local reference to this within a method for places where context is lost (ie... within a callback). If this is just an object literal that has been created to pass into the block as the context, I think I'm better off just using a local variable and not leveraging the this context.
or as an argument
versus
I think self is just as readable as this and self will obfuscate where as this will not.
On another note, in your post above you say all functions are actually methods and all belong to an object, but this is not actually true if declared within a closure.
or ( same result )
These examples belong to the local execution scope of their respective closures but not an accessible object.
@nelle
The script you posted is capable of currying a function as well. It can accept additional arguments and apply them as well as the context. If you want a script that only binds the this and doesn't have the additional overhead, you could use:
or on the prototype
Also I've been trying to wrap my head around the nop and bound prototype use in the script you posted. It seems like it is an attempt to make it safe to bind constructors. I don't know of a use case for that. Can anyone else think of one?
@Bob What you have for the Bind is wrong.
here is the right way of doing it
so in this case this will return a new function and changes the scope. which is different from call and apply.
@Ben
@Bob
We can say All functions in the Global Scope are Methods :)
@mahdi,
Neither snippet is right or wrong. Your example will bind the context as well as arguments. Mine will only bind the context.
If you're not passing additional arguments beyond the context ( which I often don't ), there is no need to slice the arguments. If you wish to bind arguments as well, I would use something similar to nelle's post. It will allow for partial application by concatenating additional arguments on execution of the newly bound function. Your example will not. Assuming the function in your example is not reaching to any outer variables, it will always have the same result which isn't very flexible.
As Ben states in the above post the difference between call and apply is only in the method signature.
@Bob
I am not passing extra arguments don't get confused I am passing the arguments that the function expects to get.
but in your code arguments in sencond function is an empty array cause you are loosing the reference :)
I hope this made it clear for you
Ben, thanks for taking the time to document this!
Personally, I like more the first post since it is more like application of the theory described in the second.
The only thing that I see a little misleading is the title. "Changing The Execution Context…" sounds like we are changing the whole context. As you most probably know the execution context have three major properties - variableObject, scopeChainArray and thisObject. You are talking only about changing its third property.
For those who don't know this check out the amazing article by Dmitry Soshnikov at http://dmitrysoshnikov.com/ecmascript/javascript-the-core/#execution-context
//Plamen
@WebManWalking,
I try not to think too much about infinite loops - it hurts my head :) I think, though, that if the objects are all using the Prototype chain then it must be linkable in a non-crazy way. It's like in ColdFusion when you CFDump something with a circular reference - it can (or used to) cause a stack overflow; but that doesn't mean that it doesn't work in practice.
That said, the Prototype chain still bends my mind in circles :) I've tried to codify some thoughts:
www.bennadel.com/blog/2232-Understanding-The-Complex-And-Circular-Relationships-Between-Objects-In-JavaScript.htm
Even so, I have to think about it deeply every time I use stuff.
@Nelle,
The concept of function binding is pretty badass! In the jQuery world, they finally added the concept of Proxying, which is exactly what the Bind function doesn:
http://api.jquery.com/jQuery.proxy/
It basically links a function to an execution context no matter how it gets called. What's extra cool in the jQuery world is that the Proxy method allows for functions to be bound/unbound as event handlers regardless of whether or not they have been proxied.
@Bob,
I'm glad you like the things that I write up. And good catch about the functions that are part of the active local scope of a function - I hadn't considered that when I was talking about functions vs. methods. Excellent catch!
The nice thing about using an explicit (var self) method is that it's very explicit and, therefore, should be great for both readability and maintainability. And, you can never underestimate the power of such things! A lot of the stuff I write about doesn't necessarily make it to "production" code; I find that I can generate some good ideas (and great conversation) from digging into the alternate implementations. And, that's the greatest part.
@Plamen,
Thanks for the kind words. And you are correct in that only part of the context is actually changed - the "this" object. Anything that was bound as part of the closure will continue to be bound to the original context, no matter what. Closure are so freaking awesome.
I'll take a look at the link you shared, thanks!
Your first two code examples don't actually include the 'this' keyword, although your explanations indicate that they do:
==========================================
sarah.sayHello();
... the "this" keyword within the sayHello() method is a reference to the sarah object.
Similarly, in this code:
getScreenResolution();
... the "this" keyword within the getScreenResolution() function is a reference to the window object (since unbound functions are implicitly bound to the global scope).
@Scott,
While the "this" reference is not actually used in those examples, previously in the post, I stated that every function body has access to the "this" reference. And, that that reference changed based on the way the functions were invoked. Reading it back now, however, I can see that it can be confusing. Rather than using "...", I should have put *some* reference to it, such as:
Image that "console.log( this )" was in the *body* of each of the defined methods in the first two examples and that should help clarify the situations.
Thanks for pointing this out - sometimes, when I write something, I have so much whirling around in my head that I don't realize what kind of leaps people will have to make in their understanding.
Is there any way to achieve similar functionality in Coldfusion? I need a way to call() or apply() in Coldfusion as well to dynamically bind my 'this' variable.
Great!! Great!!! Great!!! ... especially your graph, It explains everything. I came back here few times writing "JavaScript - call() and apply()" at http://blog.i-evaluation.com/2012/08/15/javascript-call-and-apply.Very useful post. Thanks a lot!
Very well written. Simple and to the point. There are so many blogs around by many experts but none did such a good job of explaining the context as yours in my quick google search.
Thanks, and I am back to my coding now.