O'Reilly logo

JavaScript Web Applications by Alex MacCaw

Stay ahead with the world's most comprehensive technology and business learning platform.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, tutorials, and more.

Start Free Trial

No credit card required

Chapter 4. Controllers and State

Historically, state was managed server side with session cookies. So, whenever users navigated to a new page, the previous page’s state was lost—only the cookies persisted. JavaScript applications, however, are confined to a single page, which means we can now store state on the client's memory.

One of the major advantages to storing state on the client is a really responsive interface. A user gets immediate feedback when interacting with the page, rather than waiting a few seconds for the next page to load. Speed greatly improves the user experience, making many JavaScript applications a real pleasure to use.

However, storing state on the client causes challenges as well. Where exactly should it be stored? In local variables? Perhaps in the DOM? This is where a lot of developers get led astray, which is an unfortunate state of affairs because storing state properly is one of the most critical areas to get right.

First, you should avoid storing data or state in the DOM. That’s just a slippery slope leading to an entangled mess and anarchy! In our case—since we’re using the tried and tested MVC architecture—state is stored inside our application’s controllers.

What exactly is a controller? Well, you can think of it as the glue between the application’s views and models. It’s the only component aware of the application’s views and models, tying them together. When the page loads, your controller attaches event handlers to views and processes callbacks appropriately, interfacing with models as necessary.

You don’t need any libraries to create controllers, although they can be useful. The only essential part is that controllers are modular and independent. Ideally, they shouldn’t be defining any global variables, instead functioning as fairly decoupled components. An excellent way of ensuring this is with the module pattern.

Module Pattern

The module pattern is a great way to encapsulate logic and prevent global namespace pollution. It’s all made possible by anonymous functions, which are arguably the single best feature of JavaScript. We’ll just create an anonymous function and execute it immediately. All the code residing within the function runs inside a closure, providing a local and private environment for our application’s variables:

(function(){
  /* ... */
})();

We have to surround the anonymous function with braces () before we can execute it. JavaScript requires this so it can interpret the statement correctly.

Global Import

Variable definitions inside the module are local, so they can’t be accessed outside in the global namespace. However, the application’s global variables are all still available, and they can be readily accessed and manipulated inside the module. It’s often not obvious which global variables are being used by a module, especially when your modules get larger.

In addition, implied globals are slower to resolve because the JavaScript interpreter has to walk up the scope chain to resolve them. Local variable access will always be faster and more efficient.

Luckily, our modules provide an easy way to resolve these problems. By passing globals as parameters to our anonymous function, we can import them into our code, which is both clearer and faster than implied globals:

(function($){
  /* ... */
})(jQuery);

In the example above, we’re importing the global variable jQuery into our module and aliasing it to $. It’s obvious which global variables are being accessed inside the module, and their lookup is quicker. In fact, this is the recommended practice whenever you want to use jQuery’s $ shortcut, which ensures that your code won’t conflict with any other libraries.

Global Export

We can use a similar technique when it comes to exporting global variables. Ideally, you should be using as few global variables as possible, but there’s always the odd occasion when they’re needed. We can import the page’s window into our module, setting properties on it directly, thereby exposing variables globally:

(function($, exports){

  exports.Foo = "wem";

})(jQuery, window);

assertEqual( Foo, "wem" );

The fact that we’re using a variable called exports to set any global variables means the code is clearer, making it obvious which global variables a module is creating.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, interactive tutorials, and more.

Start Free Trial

No credit card required