Closures

You’ll see closures a lot in JavaScript. The reasons for this are:

  1. In JavaScript, Bind is transient.
  2. It is callback functions attached to DOM elements that respond to events.
  3. Most code attaches callbacks to individual DOM elements (rather than delegating to a parent element).

Test code

Here’s the test code for closures.

TEST('closures', function()
{
    // A factory for creating get-set pairs.
    var get_set_factory = function(){

        var value;
        var get = function(){
            return value;
        };
        var set = function(new_value){
            value = new_value;
        };

        return {
            get: get,
            set: set
        };
    };

    // Create and unpack two get-set pairs.
    var tmp;
    tmp= get_set_factory();
    var get_a = tmp.get;
    var set_a = tmp.set;

    tmp= get_set_factory();
    var get_b = tmp.get;
    var set_b = tmp.set;

    // Test that both pairs work.
    set_a(12);
    assert( get_a() === 12 );

    set_b(13);
    assert( get_b() === 13 );

    // Test that each pair has its own value.
    assert( get_a() === 12 );

});

Discussion

The factory function creates two functions, get and set, which refer to the variable value of the factory function. The get function returns the value of this variable, while the set function changes it.

To test the factory function we create two get-set pairs. We then test that each set operation changes the value return by its partner get operation.

Finally, we test that the two pairs don’t interfere with each other.

Explanation

Objects continue to exist so long as a reference remains to them. When the last reference to an object is removed (or when the object is part of cyclic garbage) the object can be destroyed. When the return value of a function is stored (say as the value of a variable) then this return value continues to exist. Similarly, anything referred to by the return value continues to exist.

Closures come about when the return value of a function is itself a function defined within the outer function (or contains references to such functions).

Suppose the outer function returns an inner function (or in other words a function that is defined within the outer function). Suppose also that the inner function uses a variable (or parameter) of the outer function. In this situation the inner function holds a reference to the value of this variable. The code in the inner function can read (or get) this value. It can also write to this variable.

One final point. Each call of the outer function creates a new instantiation of the function variable.

Exercises

A programmer, perhaps in a hurry, misses out a var in the example above. So now it reads:

var get_set_factory = function(){

   value;   // Here's the missing *var*.
  1. Which tests to you expect to pass, and which to fail?
  2. Make this change and run the tests. Which actually fail?
  3. Explain what is happening.
  4. What does this tell us about coding and testing?