Advertisement
  1. Code
  2. JavaScript

Closures: Front to Back

Scroll to top
9 min read

Closures are often viewed as an arcane art in the land of JavaScript. Once mastered, they allow you to write some truly amazing JavaScript. This article will get you up to speed on the magic of JavaScript closures.


What Is A Closure?

One of the key truths of JavaScript is that everything is an object. This, of course, includes functions.

A closure is nothing more than a function object with a related scope in which the function's variables are resolved.

Closures get their name because of the way they close over their contents. Consider the following bit of JavaScript:

1
2
topping = "anchovi";
3
function pizzaParty(numSlices) {
4
	var topping = "pepperoni",
5
6
	innerFunction = function() {
7
		var topping = "ham";
8
		console.log(" .....But put " + topping + " on " + numSlices + " slices");
9
	};
10
11
	console.log("This pizza is all about the " + topping);
12
13
	innerFunction();
14
}
15
pizzaParty(3);

If you open up your favorite console and run that bad boy, you will be greeted with a delicious message to the effect of "This pizza is all about the pepperoni ..... But put ham on 3 slices." This example illustrates some key concepts of JavaScript that are crucial to getting a hold on closures.

A Closure is a Function Object

How many function objects are in the above code? Well... we have our pizzaParty function, and nested in that function is innerFunction. Math hasn't always been my strong suit, but 1 + 1 = 2 in my book. Each function object has its own set of variables, which are resolved in each function's scope.

A Closure Has its Own Scope

Closures can't be fully understood without a firm grounding in scope. JavaScript's scope mechanism is what allows each function to have its own topping variable, and without it we might have too much pepperoni, too little ham, or *gasp* ... some anchovies at our pizza party. Let's use a quick illustration to better illustrate this idea.

Functions are executed using the scope that was in effect when the function was defined. It has nothing to do with the scope in effect when the function is called.

Variable Accessibility Works Outside-In

The green arrows show that accessibility works from the outside in. Variables defined in the scope outside of a function are accessibile from within it.

If we were to omit the topping variable from inside the pizzaParty function, then we would get a message like "This pizza is all about the anchovi", but since pizzaParty has a topping variable within its own scope; those salty suckers will never get near our pizza party.

Likewise, the numSlices parameter can be accessed from within innerFunction because it is defined in the scope above - in this case the scope of pizzaParty.

Variable Accessibility Does Not Work Inside-Out

The red arrows show that variables in scope for a function are never accessible outside of that function. This is the case only when a variable meets one of the following conditions:

  1. The var keyword is being used.
  2. The variable is a parameter to the function or an outer function.
  3. The variable is a nested function.

Omitting the var keyword when setting a variable will cause JavaScript to set the closest named variable in outer functions all the way up to the global scope. So, using our example, the ham topping in innerFunction cannot be accessed from pizzaParty, and the pepperoni topping in pizzaParty cannot be accessed out in the global scope where the anchovi dwells.

JavaScript Uses Lexical Scoping

Lexical scope means functions are executed using the variable scope in effect when the function was defined. It has nothing to do with the scope in effect when the function is called. This fact is crucial to unlocking the power of closures.

Now that we understand what a closure is, and what scope means for closures, let's dive into some classic use cases.


Using Closures For Privacy

Closures are the way to conceal your code from the public eye. With closures, you can easily have private members that are shielded from the outside world:

1
2
(function(exports){
3
4
	function myPrivateMultiplyFunction(num,num2) {
5
		return num * num2;
6
	}
7
8
	//equivalent to window.multiply = function(num1,num2) { ...

9
	exports.multiply = function(num1,num2) {
10
		console.log(myPrivateMultiplyFunction(num1,num2));
11
	}
12
13
})(window);

With closures, you can easily have private members that are shielded from the outside world.

Let's break it down. Our top level function object is an anonymous function:

1
2
(function(exports){
3
	
4
})(window);

We invoke this anonymous function right away. We pass it the global context (window in this case) so we can "export" one public function, but hide everything else. Because the function myPrivateMultiplyFunction is a nested function, it exists only within the scope of our closure; so we can use it anywhere inside this scope, and only in this scope.

JavaScript will hold a reference to our private function for use inside the multiply function, but myPrivateMultiplyFunction cannot be accessed outside of the closure. Let's try this out:

1
2
multiply(2,6) // => 12

3
myPrivateMultiplyFunction(2,6) // => ReferenceError: myPrivateMultiplyFunction is not defined

The closure has allowed us to define a function for private use, while still allowing us to control what the rest of the world sees. What else can closures do?


Using Closures For Meta-Programming

Closures are quite handy when it comes to generating code. Tired of remembering all those pesky key codes for keyboard events? A common technique is to use a key map:

1
2
var KeyMap = {
3
	"Enter":13,
4
	"Shift":16,
5
	"Tab":9,
6
	"LeftArrow":37
7
};

Then, in our keyboard event, we want to check if a certain key was pressed:

1
2
var txtInput = document.getElementById('myTextInput');
3
txtInput.onkeypress = function(e) {
4
	var code = e.keyCode || e.which //usual fare for getting the pressed key

5
	if (code === KeyMap.Enter) {
6
	    console.log(txtInput.value);
7
	}
8
}

Capturing A Moment In Time

The above example isn't the worst, but we can use meta-programming and closures to make an even better solution. Using our existing KeyMap object, we can generate some useful functions:

1
2
for (var key in KeyMap) {
3
4
	//access object with array accessor to set "dyanamic" function name

5
	KeyMap["is" + key] = (function(compare) {
6
		return function(ev) {
7
			var code = ev.keyCode || ev.which;
8
			return code === compare;
9
		}
10
	})(KeyMap[key]);
11
12
}

Closures are so powerful because they can capture the local variable and parameter bindings of the function in which they are defined.

This loop generates an is function for every key in KeyMap, and our txtInput.onkeypress function becomes a bit more readable:

1
2
var txtInput = document.getElementById('myTextInput');
3
txtInput.onkeypress = function(e) {
4
	if(KeyMap.isEnter(e)) {
5
		console.log(txtInput.value);
6
	}
7
}

The magic starts here:

1
2
KeyMap["is" + key] = (function(compare){
3
	
4
})(KeyMap[key]); //invoke immediately and pass the current value at KeyMap[key]

As we loop over the keys in KeyMap, we pass the value referenced by that key to the anonymous outer function and invoke it immediately. This binds that value to the compare parameter of this function.

The closure we are interested in is the one we are returning from inside the anonymous function:

1
2
return function(ev) {
3
	var code = ev.keyCode || ev.which;
4
	return code === compare;
5
}

Remember, functions are executed with the scope that was in place when they were defined. The compare parameter is bound to the KeyMap value that was in place during a loop iteration, and so our nested closure is able to capture it. We take a snapshot in time of the scope that was in a effect at that moment.

The functions we created allow us to skip setting up the code variable everytime we want to check the key code, and we now have convenient, readable functions to use.


Using Closures To Extend The Language

At this point, it should be relatively easy to see that closures are vital to writing top notch JavaScript. Let's apply what we know about closures to augmenting one of JavaScript's native types (gasp!). With our focus on function objects, let's augment the native Function type:

1
2
Function.prototype.cached = function() {
3
	var self = this, //"this" refers to the original function

4
		cache = {}; //our local, lexically scoped cache storage

5
	return function(args) {
6
		if(args in cache) return cache[args];
7
		return cache[args] = self(args);
8
	};
9
};

This little gem allows any and every function to create a cached version of itself. You can see the function returns a function itself, so this enhancement can be applied and used like so:

1
2
Math.sin = Math.sin.cached();
3
Math.sin(1) // => 0.8414709848078965

4
Math.sin(1) // => 0.8414709848078965 this time pulled from cache

Notice the closure skills that come into play. We have a local cache variable that is kept private and shielded from the outside world. This will prevent any tampering that might invalidate our cache.

The closure being returned has access to the outer function's bindings, and that means we are able to return a function with full access to the cache inside, as well as the original function! This small function can do wonders for performance. This particular extension is set up to handle one argument, but I would love to see your stab at a multiple argument cache function.


Closures in the Wild

As an added bonus, let's take a look at a couple uses of closures in the wild.

jQuery

Sometimes, the famous jQuery $ factory is not available (think WordPress), and we want to use it in the way we typically do. Rather than reach for jQuery.noConflict, we can use a closure to allow functions inside to have access to our $ parameter binding.

1
2
(function($){
3
	$(document).ready(function(){
4
		//business as usual....

5
	});
6
})(jQuery);

Backbone.js

On large Backbone.js projects, it might be favorable to have your application models private, and then expose one public API on your main application view. Using a closure, you can easily acheive this privacy.

1
2
(function(exports){
3
4
var Product = Backbone.Model.extend({
5
    urlRoot: '/products',
6
});
7
8
var ProductList = Backbone.Collection.extend({
9
    url: '/products',
10
    model: Product
11
});
12
13
var Products = new ProductList;
14
15
var ShoppingCartView = Backbone.View.extend({
16
17
    addProduct: function (product, opts) {
18
        return CartItems.create(product, opts);
19
    },
20
21
    removeProduct: function (product, opts) {
22
        Products.remove(product, opts);
23
    },
24
25
    getProduct: function (productId) {
26
        return Products.get(productId);
27
    },
28
29
    getProducts: function () {
30
        return Products.models;
31
    }
32
});
33
34
//export the main application view only

35
exports.ShoppingCart = new ShoppingCartView;
36
37
})(window);

Conclusion

A quick recap of what we learned:

  • A closure is nothing more than a function object with a scope.
  • Closures get their name by the way they "close" over their contents.
  • Closures cash in big time on JavaScript's lexical scope.
  • Closures are the way to achieve privacy in JavaScript.
  • Closures are able to capture the local variable and parameter bindings of an outer function.
  • JavaScript can be powerfully extended with some closure magic.
  • Closures can be used with many of your favorite libraries to make them even cooler!

Thanks so much for reading! Feel free to ask any questions. Now let's enjoy the pizza party!

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.