JavaScript Method Context With Circular Invocation In Conjunction With Call() Or Apply()

Posted April 24, 2012 at 10:04 AM by Ben Nadel

Tags: Javascript / DHTML

In JavaScript, you can change part of the execution context using the call() and apply() methods. These allow you to explicitly define the binding of "this" at the time of method invocation. While I use these functions all the time, I realized recently that I was unsure what would happen if you created a circular invocation chain using an overridden method. To ease my mind, I created a small experiment:

  • <!DOCTYPE html>
  • <html>
  • <head>
  • <title>Testing JavaScript Context</title>
  •  
  • <script type="text/javascript">
  •  
  •  
  • // For this test, we are going to look at how circular
  • // method invocations work in the context of a method
  • // that has been invoked with either call() or apply().
  • var testHarness = {
  •  
  • one: function(){
  • console.log( "Real Context!" );
  • },
  •  
  • two: function(){
  • this.one();
  • }
  •  
  • };
  •  
  •  
  • // -------------------------------------------------- //
  • // -------------------------------------------------- //
  •  
  •  
  • // To test the circular invocation and this-based context,
  • // we need to override the "one" method, and have it invoke
  • // the "two" method so we can then see what version of "one"
  • // it will turn around and invoke.
  • function one(){
  •  
  • console.log( "FAKE Context!" );
  •  
  • // Create circular invocation.
  • this.two();
  •  
  • }
  •  
  •  
  • // -------------------------------------------------- //
  • // -------------------------------------------------- //
  •  
  •  
  • // Invoke "fake" ONE in the context of the test harness.
  • one.call( testHarness );
  •  
  •  
  • </script>
  • </head>
  • <body>
  • <!-- Left intentionally blank. -->
  • </body>
  • </html>

Here, we have a test object with two methods: one() and two(). In its natural state, two() invokes one() but, one() never invokes two(). Then, we create a completely separate function which overrides the "one" method and invokes two(). Does this create a circular reference problem?

When we run the above code, we get the following console output:

FAKE Context!
Real Context!

When we run the the override method, we clearly get the fake (ie. explicitly changed) context. But, when that function invokes two(), which subsequently invokes one(), the "second" invocation of one() reveals that its context is the original context.

No circular references were created.

When I saw this, I suddenly had clarity - I realized that my previous mental model of call() and apply() was completely wrong. I kept thinking about it as some sort of temporary, runtime method injection magic. I kept thinking about it as overriding part of the target context's object definition. In reality, it's nothing more than an overriding of the given method's "this" binding. There's nothing more to it. There's no relationship between the method being invoked and the context that is being applied.

In retrospect, this should have been completely obvious. I guess at some point, I had just created a false mental model of how things worked and never stopped to question it. Clarity for the win!




Reader Comments

Apr 24, 2012 at 10:21 AM // reply »
8 Comments

Thanks for this clarity.
I have not tested it yet but yeah, it's obvious. Apply and call simply override the context and do not create a "mixin context" who contains both the second one() and the two().

I don't remember if it was detailled in, but I found a very well explanation of the javascript core: http://dmitrysoshnikov.com/ecmascript/javascript-the-core/


Apr 24, 2012 at 10:46 AM // reply »
11,238 Comments

@Loic,

I think part of my distortion came from the fact that my primary programming language - ColdFusion - doesn't have a call() or apply() equivalent. As such, in that language, you actually DO have to fine way to use method injection rather than overriding the "this" binding. So, while I know how call() and apply() work, it was being colored improperly by my understanding of a different language altogether.


Post A Comment

Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.

Please review the following issues:

Author Name:


Author Email:

Author Website:

Comment:

Supported HTML tags for formatting: <strong>bold</strong>   <em>italic</em>   <code>code</code>







  • Help Wanted - Find Your Next ColdFusion Job
Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
May 20, 2013 at 4:38 PM
Using A Dynamic Column Name With ValueList() In ColdFusion
@Dana, Your confusion is well founded, since this is a very confusing features. In fact, it ONLY works if you use array notation. Meaning, that this: arrayToList( query[ "columnName" ] ) ... read »
May 20, 2013 at 4:34 PM
Using A Dynamic Column Name With ValueList() In ColdFusion
I was thinking chicken and the egg, I wouldn't have expected it to work in the valuelist going in I guess. Maybe I just need a beer, long day :) ... read »
May 20, 2013 at 4:29 PM
Using A Dynamic Column Name With ValueList() In ColdFusion
@Dana, That's if you're trying to reference a specific row. In this case, we're trying to reference the entire query column as one cohesive value. So, you are correct that if you wanted to output a ... read »
May 20, 2013 at 4:24 PM
Using A Dynamic Column Name With ValueList() In ColdFusion
I thought when you used array notation to reference queries you always had to have the row or it would throw a similar error as well? ... read »
May 20, 2013 at 11:45 AM
Using jQuery's Animate() Step Callback Function To Create Custom Animations
This is really useful. I found out that you don't actually have to use a dummy css property (surprisingly). To animate a property in a linear-gradient for instance I did this this.css('someLinearGra ... read »
May 20, 2013 at 10:51 AM
Using A Dynamic Column Name With ValueList() In ColdFusion
@Josh, Oh snap! You're totally right! I'm not sure I've ever tried that. I did know that you can call a number of other array-methods on ColdFusion query columns: http://www.bennadel.com/blog/167 ... read »
May 20, 2013 at 10:45 AM
Using A Dynamic Column Name With ValueList() In ColdFusion
@Ben - I believe you can achieve the same functionality with ColdFusion's built in ArrayToList() function. ArrayToList( users[ "id" ] ); ... read »
May 20, 2013 at 10:21 AM
My Experience With AngularJS - The Super-heroic JavaScript MVW Framework
Is there any error logging and handling framework in angularjs, if not then in what way I can do this. ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools