JavaScript Patterns & Grokking Closures!

| Comments

Last year I wrote a post on JavaScript closures. Another newbie programmer read that post and emailed to say, yes, that’s nice, but when practically do you use them… fast forward a few months, and I’m finally beginning to grok the beauty of closures myself.

This happened precisely because I started building - then rebuilding - my first app. I have restructured things more than once, in my attempt to investigate and wrap my brain around popular ways of organising code. Along the way, I have discovered the importance of good building blocks, as well as how to use closure to keep the guts of a program tucked away.

Here’s some code for capturing a value and building a list:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
$(document).ready(function() {
  // Define list here so available to all methods
  var $list = $('#itemsList');

  // When form submitted...
  $('form#listRandomItemsForm').on('submit', function(event) {

    // Get value
    var $input = $(this).find('input[type=text]'),
        value = $input.val().trim();

    // Add to list if there is an input value
    if (value) {
      addToItemsList(value);        
    };

    // Reset text input field to blank
    $input.val('').focus();

    event.preventDefault();
  });      

  var addToItemsList = function(value) {
    var $li = $('<li />').text(value);

    $list.prepend($li);
  };   
});

This is some pretty trivial code, but we’re going to refactor it anyway, to quickly illustrate the usefulness of two common coding practices. In our examples, we are careful to keep variables out of that most messy of intersections, the global scope - a best practice achieved by all the various coding patterns available to us.

The Building Blocks For Adaptive Code

Plans have a habit of straying from the sketched path. When this happens to your application, change in one area should come easily enough, without unpredictable knock-on effects jumping up elsewhere. Such forward compatibility is greatly more achievable if we break things down into clearly defined packages of reusable code at every step and level of our program. In the following example of the object literal pattern, we define single-purpose atomic parts - the methods - in a containing object literal that groups related units of behaviour:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
var ListApp = {

  init: function() {
    // Define list as a property of ListApp, so available to all methods
    this.$list = $('#itemsList');

    // When form submitted...
    $('#listRandomItemsForm').on('submit', function(event) {

      var value = ListApp.getValue(this);

      // Add to list if there is an input value
      if (value) {
        ListApp.addToItemsList(value);
      };

      event.preventDefault();
    });
  },

  getValue: function(form) {
    var $input = $(form).find('input[type=text]');
        value = $input.val().trim();

    // Reset text input field to blank
    $input.val('').focus();

    return value;
  },

  addToItemsList: function(value) {
    var $li = $('<li />').text(value);

    this.$list.prepend($li);
  }
};

// Initialise ListApp when DOM ready 
$(document).ready(function(){
  ListApp.init();
});

For more on the object literal pattern, check out Using Objects to Organize Your Code by Rebecca Murphey.

Disappear Code With Closure

The final example shows how we can use closure to prevent misadventure when a developer interacts with our program. Only an object, which acts as a public API (used by other parts of our application, or even other applications), is returned from a self-invoking function. The returned object is automatically assigned to ListApp, but everything else in the closure is removed from general reach, so the guts of our program are protected. Here’s the code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
  var ListApp = function() {
    // Define list here so available to all methods
    var $list;

    var init = function() {
      // Cache list
      $list = $('#itemsList');

      // When form submitted...
      $('#listRandomItemsForm').on('submit', function(event) {
        var value = getValue(this);

        // Add to list if there is an input value
        if (value) {
          addToItemsList(value);
        };

        event.preventDefault();
      });
    };

    var getValue = function(form) {
      var $input = $(form).find('input[type=text]'),
          value = $input.val().trim();

      // Reset text input field to blank
      $input.val('').focus();

      return value;
    };

    var addToItemsList = function(value) {
      var $li = $('<li />').text(value);

      $list.prepend($li);
    };

    // OUR PUBLIC API
    return {
      init: init
    };
  }();

  $(document).ready(ListApp.init);

The above is an example of the module pattern popularised by JavaScript hero Douglas Crockford. Check out one of his lectures (starts 20 minutes in, at hopefully the relevant bit).

Comments