Skip to main content
Ben Nadel at Angular 2 Master Class (New York, NY) with: Albert Melgoza
Ben Nadel at Angular 2 Master Class (New York, NY) with: Albert Melgoza

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

By on

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!

Want to use code from this post? Check out the license.

Reader Comments

15,688 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.

I believe in love. I believe in compassion. I believe in human rights. I believe that we can afford to give more of these gifts to the world around us because it costs us nothing to be decent and kind and understanding. And, I want you to know that when you land on this site, you are accepted for who you are, no matter how you identify, what truths you live, or whatever kind of goofy shit makes you feel alive! Rock on with your bad self!
Ben Nadel