Skip to main content
Ben Nadel at cf.Objective() 2014 (Bloomington, MN) with: Alec Irwin
Ben Nadel at cf.Objective() 2014 (Bloomington, MN) with: Alec Irwin

Changing The Execution Context Of Your Self-Executing Function Blocks In JavaScript

By on

Over the weekend, I attended the jQuery Conference 2011 up in Boston. In the CoffeeScript presentation by Mark Bates, I saw something very interesting. When he showed us how the CoffeeScript was compiled down into JavaScript, I saw the conversion using an approach that I had never seen before: the compiler was explicitly setting the context of self-executing function blocks.

Self-executing function blocks (or IIFEs: immediately-invoked function expressions) are not methods; that is, they are not called as properties of an object. As such, they execute in the context of the global scope. This means that within the code of a self-execution function block, the "this" keyword is [generally speaking] a reference to the global scope which, in the browser, is the window object.

In JavaScript, every Function instance has two methods that can be used to change the context of its execution for a particular invocation. These methods are call() and apply(). While they each have a different method signature, both take an explicit context as their first argument. While a self-executing function block is somewhat unusual, it's still a Function instance and can, therefore, still make use of call() and apply().

To see this in action, let's take a look at the following demo. In this scenario, we are using call() to explicitly define the "this" context of the self-executing function block:

<!DOCTYPE html>
<html>
<head>
	<title>Changing The Context of a Self-Executing Function</title>

	<script type="text/javascript">


		// Set the singleton value to the return value of the self-
		// executing function block.
		var singleton = (function(){


			// Declare a private variable.
			var message = "Stop playing with your context!";


			// Declare a public method. In this function, the "THIS"
			// keyword is a reference to the object literal context
			// defined with the .call() method.
			this.getMessage = function(){

				return( message );

			};


			// Return this object reference.
			return( this );


		}).call( {} );
		// NOTE: When we are invoking the self-executing function
		// block, we are using CALL() to change the execution
		// context of the function. In this case, we are setting it
		// equal to the object literal, {}.


		// Log the singleton message.
		console.log( "Message:", singleton.getMessage() );


	</script>
</head>
<body>
	<!-- Left intentionally blank. -->
</body>
</html>

As you can see, our self-execution function is taking the general format:

( function(){ .... } ).call( newContext );

The call() method is being used to dynamically bind the execution context of the function block to the "newContext" object. In our case, the new context is an empty object literal. By doing this, it allows us to define our public methods using the "this" scope, which in my opinion, is much more readable that defining them in some massive return() statement.

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

Message: Stop playing with your context!

As you can see, "this.getMessage" was bound to the object literal context which made it a public method of the resultant singleton reference.

While I like the module pattern, I have never been a fan of defining public methods in some bloated return() statement at the end of my code. I'll be very interested to see if this dynamic context binding will make self-executing function blocks easier to define and to read. My gut is telling me yes; but, only experience will truly answer this question.

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

Reader Comments

33 Comments

This is how I do most all my JS these days (pretty close anyway). Essentially this allows objects on "this" to be "public", and "var" scoped objects to be "private".

Then, if I need a singleton I invoke like you show above. Otherwise for a "class" I do not, allowing instantiation.

Cool stuff Ben.

15,688 Comments

@Adam,

I'm glad that you're finding this approach to be useful. When I saw it yesterday in the slides, it really jumped out at me. This is the first time I've played with it, but like I said, my gut is telling me that it's gonna be sweeeeeet :)

3 Comments

If you're going to do .call on it, you don't really need the extra parentheses, do you? What I mean is, instead of this:

( function(){ .... } ).call( newContext );

Just this:

function(){ .... }.call( newContext );

Doing that with your sample code produces the same result.

383 Comments

@Ben, I love parenthesis...to me, they just seem to help me organize things in my head so much better.

6 Comments

@Bob,

In the above case the code still works without surrounding the function in parens, but if you weren't saving the result to a variable the JavaScript engine would not be able to parse it.

function() {}.call( yourContext ); //Error
var result = function() {}.call( yourContext ); //Works

whereas

(function() {}.call( yourContext ); //Works
var result = (function() {}).call( yourContext ); //Works

You'll typically see the second option primarily because it works in either case and it tells the reader that something special is going on.

This technique is similar to the IIFE that you often see where you pass in your content and add to it (instead of using this);

var result = (function( context ) { context.hello = function() {}; })( yourContext ); //Works

The reason for the extra parens is similar to the above reason. Check out Ben Alman's article for much more explanation... http://benalman.com/news/2010/11/immediately-invoked-function-expression/

1 Comments

To quote Jurassic Park: "Just because you can doesn't mean you should".

I completely, utterly disagree with the thought that this is more readable. Consider the current module pattern: if you want to see the public API, just scan to the bottom and they are spelled our explicitly for you. This is neat, clean and 100% self documenting

return {
fnSetCfg : fnSetCfg,
fnMakeInfoBox : fnMakeInfoBox,
fnEach : fnEach,
fnCloseAll : fnCloseAll,
fnHideAll : fnHideAll,
fnShowAll : fnShowAll,
fnRemoveAll : fnRemoveAll
};
}());

Now my former coworker would instead sprinkle public and private method declarations all over in the code, and it was a complete, serious PITA to go spelunking to find where capabilities were coming from in the prototype chain.

Cool? Yes. A good idea? Probably not, IMO.

15,688 Comments

@Michael,

You definitely make a good point (and extra points for quoting movies - I love movies). When you use a return() statement to define the object's public API, it does provide a consistent and quickly findable place for the method list.

On one hand, I *want* to say that you should have to look at source code to figure out what an object does - that it should be documented somewhere (or at least commented at the top of the JavaScript module file).

The *reality* of the situation is, however, that most code is NOT documented; and when it comes to code you write on a team, the chances are probably even smaller!

Ultimately, when you work on a team, you probably need to come up with something that everyone agrees upon. Being able to coordinate and maintain code is definitely the large cost over time - more important than design choice philosophies probably.

1 Comments

I agree with @Michael. I'd go further by saying that explicit code is better then implied.

Example of implied code is 'this' binding rules such as the method invocation rule or the combination of method invocation rule with baseless function rules.

This code requires multiple sweeps for human interpretation.

1 Comments

this is super! thanx man! took a little bit time, until i anderstood it! but now i can use it for my revealed modul instead. how is this pattern named?

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