Saturday, June 4, 2011

Inner Classes in JavaScript

Introduction

I know you've been there. You start a new project. You're writing fresh code. You're keeping it clean, it all makes perfect sense, and you're loving how it's shaping up. But somehow, by the time it ships, something has happened. You look at the code and think: it was elegant code at first, but now? Not so much. Darn. I'm a great programmer, why did I let it get this complicated?
Here was my answer to that question:
  • (speaking boldly) I didn't have time to make it simpler, I had a deadline. So true! Yep, everyone understands.
  • (in a softer voice) Plus, I don't really know how to make it simpler. Aha! The truth comes out.
Well, now I know a way, and I want to share it with you in this article.

Classes - One Giant Leap for Mankind

Do you remember programming in C? Not C++, just C. No? Ok, you're young and there's a good chance you're getting bored already. But if you answered yes, or if you at least know the difference between C and C++, read on.
In C, we had functions and global data, and that was that. No one was really sure which data was modified by which functions unless they wrote the code themselves, and recently! And as programs grew ever larger, the problem grew more acute, bugs were everywhere, and software developers grew increasingly unhappy. Then someone really smart came up with the idea of classes: let's encapsulate the functions and the data that they modify into a single unit called a class, and don't let anyone else modify that data. This gave us a way of dividing our large programs into a bunch of little 'programs' (classes) which were relatively independent and thus understandable. It was the single greatest leap forward in the history of programming, and once again software developers were happy because they had a way forward. A very cool, smart way forward.

JavaScript Classes

It took a while, but eventually JavaScript applications, like the C applications of yesteryear, got big enough that using classes became imperative to keep code organized. And although the language's native inheritance model forced us to write glue code to extend a class, it was a manageable omission in the language, and we plowed forward vigorously, and the web started to come alive with dynamic behavior made possible by us, the JavaScript folks. With our reputations made, we could every now and again get a little kick out of showing our code to a Java purist just to see their eyes glaze over in bewilderment. Things were good.

Widgets

Even though we now had classes and inheritance, we still had to figure out how to divide and conquer—how to carve up our application into small parts. For framework developers writing UI components like sliders, menus, checkboxes, etc, this decision was a no-brainer: each component should be a class, which we began to call a 'widget'. But for application developers, the decision was not so clear cut until we realized that we needn't think of widgets as a single component—a widget can also be a group of closely related widgets—for example, a form containing inputs and buttons. Now we could think of our application as nothing more than a hierarchy of widgets, where each widget encapsulates a discrete portion of the page, and the top-level widget is the page itself. Mission accomplished: we now had a logical way of dividing up our application in a way that seemed intuitive and manageable. But we don't have to stop there.

MicroWidgets

After dividing our application into a hierarchy of widgets, we might think our problems are over. However, within a single source file of moderate size, be it a widget or not, clarity of code can still pose a problem because within a single class, we're in an environment that looks and feels a lot like a C program again: a set of functions and a bunch of global data, no separation of concerns. Some might say: well if the class is too big to understand easily, it should be divided into smaller classes. In theory that sounds right, but oftentimes we get to a point where further division only seems to complicate matters rather than simplify them. No, what we need in this case is something like Java's inner classes—classes within classes. Is there a JavaScript equivalent of inner classes? There is. Enter what I call MicroWidgets. Perhaps you've heard of them by another name: the Singleton Pattern. Yes, dear reader, I've come all this way only to re-introduce you to the singleton pattern! But given the enormously beneficial impact classes have on code organization, it's time to revisit this pattern and see how it can be used to simplify your code within a class.

Object Literals

As Douglas Crockford pointed out, JavaScript turns out to be a remarkably elegant language thanks to features like lexical scoping via closures and also thanks to Functions being first class objects. Another awesome feature of the JavaScript language is object literals, which, thanks to the aforementioned features, can be made into actual classes, albeit Singletons only. But that's fine, singletons are perfect as inner classes. Here's an example:
Pasted Graphic 1
Primitively speaking, this is just a function that executes immediately and returns an object literal. But that object literal is a class because of how we built it. It can have private data and private methods thanks to closure, and a public interface (the object itself) thanks to functions as first class objects. Wow! Still amazing after all these years.

A MicroWidget Example

So how can we use inner classes, or as I call them, MicroWidgets, to help organize our code? Well, here's a real world example from my most recent project:
Pasted Graphic 2
This class can be called an inner class, but I like to call it a MicroWidget because indeed it is a widget in the truest sense: it binds to a discrete DOM component (a form) and provides an API that allows us to manipulate the form elements and submit the form. It's not re-usable, so there's no point in making it a separate class outside of the class in which it lives. But it does something great for us—the great thing classes always do for us: it encapsulates the methods and the data they operate on into a distinct unit, thereby removing those methods and data from the flat space of the parent class in which it lives and replacing them with a single variable,_formMgr. That brings clarity to chaos, and that is a great thing. Always was, and always will be.