Closure

Closure can be a tricky concept to get one's head around. It works like this:

  1. Functions are objects and can be declared anywhere.
  2. If I declare a function within another function, the inner function has access to the local variables of the outer function.
  3. Normally when a function exits, all it's local variables are destroyed, but…
  4. If I hang on to the inner function in some way, the local variables of the outer function are still needed by the inner function.
  5. They are still in scope, so they are not garbage collected.

This is closure in a nutshell. Here's an example:

var outer = function() {
var a = "A Local variable"
var inner = function() {
alert(a)
}
window.fnc = inner
}
outer();
fnc();

When we call outer, we define inner and assign it as an attribute of window (in other words, a global variable) inner persists after outer has exited, so the local variable a is still in scope, and still accessible to inner.

Exercise - Try it out

  1. Enter the above code and verify it works.

Self Executing Functions

It seems a bit superfluous to have to call outer to create inner. Outer only exists here to define inner, there's no need for it once inner has been made.

If only there was a way to avoid referencing outer. Thankfully there is.

Here we have a self executing function. The function is in braces, and there are braces at the end. We are declaring an unnamed function, then running it straight away, dispensing with the need for outer.

(function() {
var a = "A Local variable"
var inner = function() {
alert(a)
}
window.fnc = inner
})()
fnc();

Exercise - Guess the output

For each of the following, try to work out what the output will be. Run the code to check your answer.

1.

var a = 12;
(function() {
alert(a);
})();

2.

var a = 5;
(function() {
var a = 12;
alert(a);
})();

3.

var a = 10;
var x = (function() {
var a = 12;
return (function() {
alert(a);
});
})();
x();

4.

var a = 10;
var x = (function() {
var y = function() {
var a = 12;
};
return function() {
alert(a);
}
})();
x();

5.

var a = 10;
var x = (function() {
(function() {
a = 12; // <<< look carefully at this line.
})();
return (function() {
alert(a);
});
})();
x();

6.

var a = 10;
(function() {
var a = 15;
window.x = function() {
alert(a);
}
})();
x();

Further Reading

Read my post on "What is a closure" on Stack Overflow

Exercise - Closure and the Sandwich Calculator

Mrs Potts the school dinner lady is tired of all the global sandwich variables getting under her feet and tripping her up all the time. She needs help cleaning her kitchen. Will you help her?

She would like it very much if you would build a sandwich machine for her, but wrap it in a closure so as to keep everything neat.

1. Create a self executing function

like this:

(function() {
})();

This will be our closure and will hold the sandwich machine, keeping all it's parts nicely together.

2. Create methods

Within the closure, create three little functions to add the bread, spread the soya margarine and add the jam. These little methods should use console.log to write a string representing their action to the DOM, e.g. "Now spreading the jam!"

Assign these functions to private variables, we don't want any of the children breaking in to the closure and spreading jam all over the place.

Now, also within the closure create a makeSandwich function which calls the three other methods in sequence, writing the sandwich instructions to the DOM.

3. Smuggle makeSandwich out of the closure

We want Mrs Potts to be able to call makeSandwich, so we need to make a global variable which she can access from the kitchen, the news agent, a flight to Barbados, anywhere.

Assign makeSandwich to the global window object, thus smuggling it out of the closure. Refer back to the example if you need to remember how to do this.

4. Call makeSandwich from outside the closure

You can now call makeSandwich from outside the closure. Because you've used onDomReady, you'll need to call it onDomReady.

If you've succeeded well done! This is super close to 2016 best practice JavaScript!

Exercise Extension

If you'd like to take this a little further, you could make it receive an array of fillings, then output them in the sandwich.

comments powered by Disqus