Closure for new JavaScript programmers

One of the best parts of JavaScript is its functions. One of the best parts of JavaScript functions is closures. So, closures are the best-of-the-best.

This post will guide the new JavaScript programmer through the process of learning about closures.

.

Credits

The author’s experience with closures is recent, so a number of authoritative sources were used, including:

  • Many Douglas Crockford references, including his web site, books, and videos
  • Mozilla Developer Network
  • Wikipedia
  • StackOverflow
  • a few of my colleagues, including some from CDOT

.

Foundations

In your JavaScript studies so far, you have accepted and understood the declaration and initialization of Number and String objects:

var myAge = 29;
var myName = 'Peter';

From these examples, you accept and understand:

  • After a statement is executed, the named variable holds/contains the value supplied on the right side of the expression
  • The named variable is persistent – its value remains in memory, and can be used by later statements

In addition, you have accepted and understood the declaration of Object and Array objects:

var myInfo = { firstName: 'Peter', lastName: 'McIntyre', age: 29 };
var myCourses = [ 'BTP100', 'BTB110', 'BTO120', 'BTO130', 'BTC140' ];

Again, from these examples, you accept and understand that the named variables hold the values in persistent memory for later use.

Functions are first-class objects 

A JavaScript function is an object. Just like the other objects – number, string, object, array.

Therefore, just like any other object, it can be passed around as an object. If you need to, you can use it anywhere an expression is used. It can be also be an argument (to another function), or a return result from another function.

Of course, like a C function, a JavaScript function can be invoked (executed/called).

Inspecting the contents of objects

Use the Firefox Scratchpad and Web Console tools for the following examples.

.

String

This example should not be surprising to you.

var name = 'Peter';
console.log(name);
// Result is...
// Peter

.

Array

When you log an array to the console, it appears in array literal form.

var nums = ['zero', 'one', 'two', 'three', 'four', 'five'];
console.log(nums);
// Result is...
// ['zero', 'one', 'two', 'three', 'four', 'five']

.

Object

When you log an object to the console, it appears in object literal form, surrounded with parentheses:

var me = {fname:'Peter', lname:'McIntyre'};
console.log(me);
// Result is...
// ({fname:'Peter', lname:'McIntyre'})

.

Function

When you log a function to the console (first console.log statement), it appears in function literal form, surrounded with parentheses. Like above, you’re seeing the function object’s contents, which is JavaScript programming code.

However, when you log the invocation results (i.e. call the function) to the console (second or third console.log statements), you see the function’s return value.

var myName = function (firstName, lastName) {
    return firstName + ' ' + lastName;
};

console.log(myName);
// Result is...
// (function (firstName, lastName) {
//     return firstName + ' ' + lastName;
// })

console.log(myName('Peter', 'McIntyre'));
// Result is...
// Peter McIntyre

// Alternative - create a variable to hold the function invocation results
var result = myName('Peter', 'McIntyre');
console.log(result);
// Result is...
// Peter McIntyre

.

What is a JavaScript closure?

In JavaScript, a closure is a function that’s enclosed in a function.

The inner function – the closure – has access to the outer function’s variables and parameters (i.e. its context).

The closure can be:

  • a function literal, assigned to a variable in the outer function
  • a function literal, assigned as the outer function’s return value (or as part of an object that’s returned)
  • a named function in the outer function

.

Benefits of closure 

Your code benefits from closure in a number of ways, which you will grow to understand:

  • Control structure definition (i.e. execution units, modularity)
  • State preservation
  • Information hiding
  • Performance

.

OK… show me some code!

This example simply increments a counter every time it’s invoked. Based on a Wikipedia example.

var incrementer = function() {
    var count = 0;
    return function () {
        return ++count;
    };
}

The inner anonymous function (on line 3) has access to the outer function’s ‘count’ variable. (If the outer function had parameters, it would also have access to those.) The ‘count’ variable is NOT accessible from outside the ‘incrementer’ function. (Try this yourself – console.log(count.toString()).)

Now, let’s examine ‘incrementer’.

console.log(incrementer);
// Displays the JavaScript code for the 'incrementer' function

// Invoke the 'incrementer' function, and assign it to a new 'inc' variable
var inc = incrementer();
console.log(inc);
// Displays the JavaScript code for the return result,
// which is JavaScript code for the inner anonymous function

// Finally, invoke the 'inc' function a few times
console.log(inc()); // returns 1
console.log(inc()); // returns 2
console.log(inc()); // returns 3

.

This example builds on the previous one. It enables a counter to be incremented, decremented, and returned.

var counter = (function() {
  var privateCounter = 0;
  function changeBy(val) {
    privateCounter += val;
  }
  return {
    increment: function() {
      changeBy(1);
    },
    decrement: function() {
      changeBy(-1);
    },
    value: function() {
      return privateCounter;
    }
  }
}());

Notice that the outer function has a named function – ‘changeBy’. It will not be visible from outside the function (and neither will the ‘privateCounter’ variable).

Notice also that the outer function’s return value is an object. The object has three properties. All three are functions.

Finally, notice that when ‘counter’ was declared (on line 1), the invocation result was assigned. You can see this on line 17, with the presence of the ‘()’ parentheses pair. (To avoid ambiguity, the entire right side of the expression that begins on line 1 was also wrapped in parentheses.)

Therefore, what is assigned to ‘counter’ is an object – the invocation result.

Now, let’s examine ‘counter’.

console.log(counter);
// Displays the invocation result, which is an object

console.log(counter.increment);
// Displays the result's 'increment' property, which is JavaScript code

console.log(counter.increment());
// The return result is 'undefined', but the function DID execute

// Finally, invoke the object's methods
// 'increment', 'decrement', and 'value'

console.log('Counter value  ' + counter.value()); // returns 2

counter.increment();
counter.increment();
console.log('Two increments ' + counter.value()); // returns 4

counter.decrement();
console.log('Decrement      ' + counter.value()); // returns 3

.

The next example is a simple full-function calculator. It’s invoked when declared and assigned, and returns an object with methods for add, subtract, multiply, and divide.

var calc = (function () {
    var base = 0;

    return {
        init: function (n) {
            base = n;
            return base;
        },
        add: function (n) {
            base += n;
            return base;
        },
        sub: function (n) {
            base -= n;
            return base;
        },
        mul: function (n) {
            base *= n;
            return base;
        },
        div: function (n) {
            base /= n;
            return base;
        }
    };
}());

Notice that the function is invoked. Therefore, the invocation result – an object with five methods – is assigned to the ‘calc’ variable.

Let’s examine this function’s contents, and invoke the returning object’s methods.

//console.log(base); // Exception: base is not defined
// Reason? 'base' is not visible outside the outer function

//console.log(calc); // displays the invocation result - an object

//var c = calc(); // Exception: calc is not a function
// Reason? You cannot invoke an object

// Assign the invocation result of the function to 'c'
var c = calc;

// Call the methods...
c.init(55);
console.log(c.add(3));    // 58
console.log(c.add(3));    // 61
console.log(c.sub(43));   // 18
console.log(c.mul(14.8)); // 266.40000000000003 - ack!
console.log(c.div(4.7));  // 56.68085106382979

.

Our final example is from Douglas Crockford‘s video that introduced you to closures. The segment runs from 11:30 through to 15:00 (about 3 1/2 minutes).

Here’s the first version, which does NOT use a closure:

// Version 1
// Bad design
// Problem... global variable 'names1', which may conflict with
// another global object

var names1 = ['zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine'];

var digit_name1 = function (n) {
    return names1[n];
};

console.log('names1 variable      - ' + names1[1]);
console.log('digit_name1 function - ' + digit_name1(1));
//

In version 2, the global problem is fixed, but it’s still a poor performer:

// Version 2
// Improved, but not perfect
// Problem... the 'names2' variable (data structure) is built
// every time the 'digit_name2' function is called

var digit_name2 = function (n) {
    var names2 = ['zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine'];

    return names2[n];
};

// the following line wouldn't work, because 'names2'
// is scoped to the 'digit_name2' function and isn't visible outside
// console.log('names2 variable      - ' + names2[2]);

console.log('digit_name2 function - ' + digit_name2(2));
//

Finally, in version 3, a closure is created.

// Version 3
// Better
// The '()' at the end of the 'digit_name3' declaration INVOKES the function
// The function's result - an anonymous function - is assigned to
// the 'digit_name3' variable
// Therefore, 'names3' will be built just once, which yields better performance
// So... 'digit_name3' is a function with access to its
// outer function's variables and parameters

// FYI - the entire expression is wrapped in ( ) to eliminate ambiguity

var digit_name3 = (function () {
    var names3 = ['zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine'];

    return function (n) {
        return names3[n];
    };
}());

console.log('digit_name3 function - ' + digit_name3(3));
//

.

Summary

In JavaScript, a closure is a function that’s enclosed in a function.

The inner function – the closure – has access to the outer function’s variables and parameters (i.e. its context).

The closure can be:

  • a function literal, assigned to a variable in the outer function
  • a function literal, assigned as the outer function’s return value (or as part of an object that’s returned)
  • named function in the outer function

.

.

.

%d bloggers like this: