Closures

Contact Us or call 1-877-932-8228
Closures

Closures

Closures in JavaScript are functions that keep reference to properties from their parent-function's scope even after their parent has returned. In our earlier lesson on scope, we learned that a function always has access to variables and parameters from its own scope, from its parent's scope (as with a nested function), and from the global scope. Closures exploit this fact to keep alive the local variables: closures "remember" the environment in which they were created, long after the parent function has finished executing. We can use closures to hide private data and expose structured, protected access to how we want other code to interact with our private date. Let's look at an example:

Code Sample:

AdvancedFunctions/Demos/closures.html
<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<title>Closures</title>
</head>
<body>
	<h1>Closures</h1>
	<script>
		function counter(x) {
			return {
				increment: function() {
					x = x + 1;
				},
				get: function() {
					return x;
				}
			}
		};

		var mycounter = counter(3);
		document.write(mycounter.get()); // writes 3
		mycounter.increment();
		mycounter.increment();
		document.write('<br>' + mycounter.get()); // writes 5
		// document.write(x); // this would generate an "x is not defined error"
		x = 14;
		document.write('<br>' + mycounter.get()); // writes 5
	</script>
</body>
</html>

Code Explanation

Function counter accepts a parameter x, expected to be a number, and returns an object with two fields:

  • a function increment, which adds one to parameter x; and
  • a function get, which returns the value of parameter x.

On line 21 we set variable mycounter to counter(3), invoking function counter and passing 3 in for the parameter. We can then call mycounter.get(), to get the current value of x, and mycounter.increment() to increment x by 1.

Why is this useful? That is, why use a closure here? Because it gives us a way to initialize a variable (x, in our case) and allow actions to be performed upon it (increment it, get its current value) but also to protect it from getting or setting other than in the ways in which we want.

If we were to uncomment the code (document.write(x);) on line 26 we would get an error, since x is not defined here: we have protected x from access outside of our function counter.

Setting, on line 27, the value of x has no affect (note that line 28 still writes 5 to the screen), since the assignment on line 27 is defining a different x (one with global scope) which, while it share the same name, is different from the x parameter in our function counter.

Here is another example in which we use closures to create a function generator:

Code Sample:

AdvancedFunctions/Demos/closures2.html
<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<title>Closures</title>
</head>
<body>
	<h1>Closures</h1>
	<p>The inner function "remembers" the value of the parameter with which its parent was called:</p>
	<script>
		function add(x){
			return function(y) {
				return x + y;
			};
		}
		
		var add5 = add(5);
		document.write(add5(10));
		document.write('<br>');
		document.write(add5(7));
		document.write('<hr>');

		var add17 = add(17);
		document.write(add17(2));
		document.write('<br>');
		document.write(add17(23));
		document.write('<hr>');
	</script>
</body>
</html>

Code Explanation

Function add accepts a parameter (a number x) and returns an anonymous function, which also accepts a numeric parameter y.

On line 17 we create a variable add5 and assign to it add(5). We can then call add5(10), add5(7), etc. - the number in any of our calls gets passed in for parameter y. The inner function "remembers" the value of x (5, in this case, from our original call to add(5)) and thus we get back the value of 5 plus the number we supply.

Similarly, we can create add17 = add(17) to build a "17 adder", where calls such as add17(2) returns 17 + 2 = 19, 17 + 23 = 40, etc. We have created an "adder function generator" with closures.

In the next exercise, you will use closures to create a basic bank account application:

Next