Organizing your code into modules

When working on large applications you have to pay attention to organize your code properly. Limiting global namespace pollution and providing logical module organization are priorities, and code written using jQuery is no exception. You should take care of its structure in the same way you would do for any other code written without it.

The simple approach those starting with JavaScript adopt is to define several functions and objects in a file, as shown here:

function foo() {};
function bar() {};
function baz() {};
var obj = {};
var anotherObj = {};

The problem with this code is that all these functions and objects become global (available as properties of the window object), so sooner or later a library will come in and overwrite one of them. In addition, it doesn’t consider that you may want to keep some data private, a problem we already discussed when talking about jQuery plugins and how the jQuery library is structured.

Another problem is that if these functions and objects serve different roles and are used in different parts of the project, the only way you have to recognize those roles is by reading the names you assigned. Let’s say that you have JavaScript code for an ecommerce website, and that the obj object and the bar() function are needed for the payments part of the application, and the baz() function and the anotherObj object are required for the basket. How you can distinguish them?

Using more technical terminology, you can say that your application has two modules: payment and basket. Modules play an important role in the robust architecture of an application and, as you’ll see, help you keep the units of code for a project separate and organized. In JavaScript, there are several options for implementing modules: AMD (asynchronous module definition, discussed in section 15.3), ECMAScript 2015 (also known as ECMAScript 6), object literals, CommonJS, and others.

In the following sections you’ll learn some patterns to use to organize your code into modules.

The object literals pattern

One of the simplest techniques you can adopt to organize code into modules is to use object literals. To simplify the explanation of this approach we’ll break the discussion into simple steps.

The first step, which lets you avoid polluting the global namespace, is to “namespace” the functions, objects, and other variables you defined using an object literal:

var myService = {
   foo: function() {},
   bar: function() {},
   baz: function() {},
   obj: {},
   anotherObj: {}
}

With this small change you can access the same functions and objects as before but through one entry point. Because of that, the likelihood that a library would override your code is decreased, but you haven’t solved the issue of separating the functions and objects based on their role.

The previous approach can be extended further to solve this issue:

With this structure, you could call the baz() function of the basket module as shown here:

myService.basket.baz();

Once you have your code logically separated, you can even place each module in a different file. You might have a basket.js file, containing the basket module, defined as such:

myService.basket = {
   anotherObj: {},
   baz: function() {}
};

Thanks to the division into multiple files, different developers can easily work on a single module, reducing the chance of stepping on each other’s toes.

Although this approach solves some issues, it isn’t well suited for keeping data private that’s globally available inside the module. In other words, you need a way to create functions and objects accessible only inside the module but not outside it. (Inside a function you can create data available to that function only.) In the next section we’ll present a better methodology that’s also able to deal with this issue.

The Module pattern

The Module pattern has been adopted in JavaScript to emulate the concept of private methods and variables inside an object like in OO languages such as Java and C#. We used the term emulate because technically speaking there aren’t access modifiers like private and public in JavaScript.

The Module pattern consists of two main components: an IIFE (more on this concept in the appendix of this app) and an object to return or augment. To give you a quick grasp of the subject, here’s a simple example of code implementing this pattern:

var myFirstModule = (function() {
   return {
      foo: function() {},
      bar: function () {},
      obj: {}
   }
})();

This code creates an IIFE and inside it returns an object literal containing the functions and the objects you want to expose publicly.

At first glance, this pattern doesn’t seem very different from the previous one, but wait until the end of this section before judging. Thanks to this approach you’re able to create variables and functions accessible within the module that from the outside are inaccessible. Let’s say that you want to add to the previous code a “private” variable, called count, that keeps track of the number of times the foo() function is invoked. You also want to define a “private” function doSomethingPrivate(), which is invoked whenever the bar() function is executed. The code to achieve this goal is shown here:

Now that you have a better understanding of the Module pattern, we can introduce you to one of its variations. This variation lets you augment the basket module discussed in the previous section:

The previous code is small but employs a couple of interesting techniques. First, you assign whatever is returned by the IIFE to a property called myService defined on the window object . The IIFE has only one parameter defined, called oldMyService, that will receive the value of a previously defined window.myService property or an empty object in case it isn’t defined (that is, in case its value is falsy. This way, you can augment the myService property with another module (if it already has at least one) or create a first module.

Inside the IIFE you define a property called basket of this object that represents your module, where you define the functions and the properties you want to expose publicly . Finally, you return the augmented object . This statement is necessary if the value of window.myService was falsy and an empty object literal was passed to the IIFE.

With this last example we’ve concluded our brief overview of how to organize a project into modules. There are other patterns that we haven’t covered in this section, but now you should be ready to keep your code clean and more manageable. In the next section we’ll discuss another pattern for creating modules, called AMD, and will introduce you to RequireJS, a library created to load modules while respecting their dependencies.


Posted

in

by

Tags:

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *