JavaScript for C# developers: the Module pattern (part 4) – debugging

(For background, please check out parts 1, 2, and 3 before reading this post.)

StopwatchOne of the problems about private local variables inside closures is that you can’t see them. Well, duh, you might say, that’s what private means after all. Point taken, but there’s one scenario where it would be really nice to be able to check those enclosed (enclosured?) variables: debugging.

Now, I’m not going to get into the whole argument here about debugging versus testing. I’m of the firm belief that you should be writing unit tests as you go along (and I’m only not doing it here because the code I write for these posts is mainly pedagogical in nature). Once you have properly built a supporting unit test structure around your code, it shouldn’t matter what your local variables contain: the unit tests will test your external interfaces and if they work as expected then you’re gold as far as the behavior of your code is concerned. Anyway…

Back to our stopwatch example – the initial simple version. Now, I will admit that, as written, it’s ruddy hard to unit test this little object. That’s because I’m embedding, essentially, a random process in the middle: the current time. To properly test this I should extract out the code snippet that gets the current time (the weird-looking +new Date() statement) and build it in as an external interface that I can then mock. But let’s say I want to debug this code after I’ve called start() and before I call stop(). As written, there’s no way I can inspect the local variable startTime if I’m in a debugger. The stopwatch object is opaque.

Enter the debugger keyword. This is a reserved word in JavaScript and is designed to trigger a program breakpoint when executed. If there is no JavaScript debugger present, it’s just ignored, but if you are running under Firebug or whatever developer tools your browser provides (I use Firefox myself) the debugger will gain control and hand control over to you.

So what, you may say. Whether you have a manual breakpoint or use this fancy debugger statement, you still have the same problem: you can’t see inside the opaque stopwatch object. True. . . unless you execute the debugger statement inside the context of the closure itself.

Let’s add an inspect() method to the stopwatch object:

var stopwatch = (function () {
  var startTime = -1,

  now = function () {
    return +new Date();
  },

  start = function () {
    startTime = now();
  },

  stop = function () {
    if (startTime === -1) {
      return 0;
    }
    var elapsedTime = now() - startTime;
    startTime = -1;
    return elapsedTime;
  },

  inspect = function () {
    debugger;
  };
  
  return {
    start: start,
    stop: stop,
    inspect: inspect
  };
}());

Notice that this new function is inside the closure. If we call stopwatch.inspect() from the Firebug console, for example, the breakpoint will be triggered, and will be triggered inside the context of the closure. We will be able to see the value of startTime (and modify it if required).

In Firebug, you get something that looks like this:

Debugging a closure with debugger statement in Firebug

Now the program execution has stopped inside the closure, you can inspect the value of startTime to your heart’s content.

Inspecting local variable in a closure

Now, I’ll be the first to recognize that this technique is a little invasive – after all, you have to write this special function and expose it publicly – but it does nicely solve the “I can’t inspect the values of the locals inside my closure/module” problem.

Album cover for It Had to Be You... The Great American SongbookNow playing:
Stewart, Rod - These Foolish Things
(from It Had to Be You... The Great American Songbook)


Loading similar posts...   Loading links to posts on similar topics...

No Responses

Feel free to add a comment...

Leave a response

Note: some MarkDown is allowed, but HTML is not. Expand to show what's available.

  •  Emphasize with italics: surround word with underscores _emphasis_
  •  Emphasize strongly: surround word with double-asterisks **strong**
  •  Link: surround text with square brackets, url with parentheses [text](url)
  •  Inline code: surround text with backticks `IEnumerable`
  •  Unordered list: start each line with an asterisk, space * an item
  •  Ordered list: start each line with a digit, period, space 1. an item
  •  Insert code block: start each line with four spaces
  •  Insert blockquote: start each line with right-angle-bracket, space > Now is the time...
Preview of response