Blog.

Writing modular JavaScript without polluting the global namespace

MF

Marco Franssen /

6 min read1173 words

Cover Image for Writing modular JavaScript without polluting the global namespace

Most of you have already seen a lot of spaghetti JavaScript code. One of the reasons you are reading this article will probably be, you don't want to make the same mistakes as others have done. So let's make the next step and stop polluting the global JavaScript namespace.

Why is it bad to have all your script code available at global level?

First of all you can possibly get a lot of errors when using modules developed by others, because you used the same names for you variables etc.

The second reason is, this code can't be minified as good as the code I will show you later.

The third reason is, you are not forcing yourself well enough to write some clean JavaScript.

If you think I'm talking bullshit, you can better stop reading this article and continue giving JavaScript a bad name and scare of other developers with spaghetti code.

First of all we need to learn to write a JavaScript module. There are a lot of examples how to achieve this. This article is a in-depth description of the module pattern. Another well know example is the object literal pattern.

In my example I will use a pattern like in the first article because it will allow me to control visibility.

var shoppingCart = (function () {
  var items = [];
  var priceTotal = 0;

  var addProduct = function (product) {
    items.push(product);
    updatePriceTotal();
  };

  var removeProduct = function (product) {
    //remove product from items
    updatePriceTotal();
  };

  var updatePriceTotal = function () {
    //logic to update the priceTotal
    //use public functions on product to get the price of products
  };

  return {
    addProduct: addProduct,
    removeProduct: removeProduct,
  };
})();
var product = (function () {
  //an implementation like shoppingCart
})();

As you can see I use a very bare example, which is just enough to show you my point. We see we put all our JavaScript modules into a seperate file, which is really helpful when you need to maintain them. In the shoppingCart I gave you an example how to control visibility. The updatePriceTotal function will be private within the module.

This way of writing your code looks pretty much like writing your code in c# or Java, isn't it (except from the syntax).

But we are still polluting the global namespace. Now there are only two variables, but think of it when you complete the code I started. How many modules would be added? How much more you will be polluting the global namespace?

When opening the developer tools in for example Chrome and hitting F12 and navigating to the console tab and you type product or shoppingCart and hit the enter key you can access the objects from the global namespace.

So how can we wrap these modules in our own namespace?

(function (jsShop, window, document, undefined) {
  var product = jsShop.product;
  var shoppingCart = (jsShop.shoppingCart =
    jsShop.shoppingCart ||
    (function () {
      var items = [];
      var priceTotal = 0;

      var addProduct = function (product) {
        items.push(product);
        updatePriceTotal();
      };

      var removeProduct = function (product) {
        //remove product from items
        updatePriceTotal();
      };

      var updatePriceTotal = function () {
        //logic to update the priceTotal
        //use public functions on product to get the price of products
      };

      return {
        addProduct: addProduct,
        removeProduct: removeProduct,
      };
    })());
})((window._jsShop = window._jsShop || {}), window, document);
(function (jsShop, window, document, undefined) {
  var product = (jsShop.product =
    jsShop.product ||
    (function () {
      //an implementation like shoppingCart
    })());
})((window._jsShop = window._jsShop || {}), window, document);

As you can see we build a little wrapper around our modules. This wrapper is a self executing function which provides access to the elements from the global namespace. When calling this anonymous self executing function we provide our own namespace which we register at global level. We also provide window, document and undefined, because this gives advantages in performance and minification of your scripts. When you never use them in your script you don't need to add them, but as a best practice I always add them so I will never forget them. Please note that the last parameter isn't provided, so it is undefined.

Another best practice is to start each script with a semicolon, so you don't have to bother about missing semicolons in other scripts. By starting with one at least this script file will not give errors on behalf of missing semicolons in other files. Issues most of the time occur when minifying your scripts.

Last but not least we have to register our module in our namespace. What we do is checking if the module already exists or else replace it with your module definition.

You may be asking, what if I want to use jQuery or whatever other script? Just add it to the wrapper so you can use it in you module.

(function ($, jsShop, window, document, undefined) {
  var yourModule = (jsShop.yourModule =
    jsShop.yourModule ||
    (function () {
      //your module code
      $("#shoppingCatTotalPrice").html("€ 8,75");
    })());
})(jQuery, (window._jsShop = window._jsShop || {}), window, document);

Now we have achieved product and shoppingCart are not polluting the global namespace anymore. As you may already have noticed I used an _ in my namespace just to give a little bit more insurance it isn't used by another external JavaScript. You can test this by opening the developer tools in for example Chrome and hitting F12. Try it out by typing   _jsShop and hitting enter, you should see everything registered in the _jsShop namespace. Google Analytics for example uses the same naming conventions. They're using the _gac variable to provide you access to their api.

If you want to read more about JavaScript namespacing you should read this article. In this example I used one of the preferred patterns of Addy Osmani.

By writing your JavaScript like I described above, it will be very easy to use require.js to load your JavaScript dependencies asynchronously. For now see Addy Osmani's article about AMD (Asynchronous Module Definition) to make the next step, until I finished my own, step by step article, which will proceed where I stopped in this article.

Also have a look at my jQuery events contributes to clean Javascript article, for a deeper dive into JavaScript modules working with events and jQuery. Note I didn't use proper name-spacing here, but you know how to add it now.

Hope you enjoyed this article and we can build together on better JavaScript code. Share it with your friends and colleagues and give me some feedback so I can learn from you.

As a last advice…

Subscribe to Addy Osmani's RSS Feed.

You have disabled cookies. To leave me a comment please allow cookies at functionality level.

More Stories

Cover Image for Install Windows 8 Consumer preview on vhd

Install Windows 8 Consumer preview on vhd

MF

Marco Franssen /

In a previous blog post I explained to you how to install Windows 8 developer preview on vhd, so you can boot from your vhd. Since there have changed a few small things I just add an updated manual below. The installation will take about 30 minutes. Step 0 Make sure you have at least 40Gb of free disk space for your vhd. Make sure you're running Windows 7. Step 1 Download the Windows 8 consumer preview. Download the Windows 7 USB/DVD tool to make yourself a bootable usb stick. Use the tool…

Cover Image for Pitching equals invisible convincing

Pitching equals invisible convincing

MF

Marco Franssen /

During the last year I learned and read a lot about convincing people. In this article I want to share some tricks to apply it yourself. Oh, its my first non technical article. So this will be a milestone for myself :D. It isn't always as easy to convince someone. Some people just manage to get more things done as others. A part of your skills to convince someone is in your own personality. To convince someone you have to be powerful, special and kind. This means you need to know where you're t…

Cover Image for Auto retry concurrent commands with ncqrs

Auto retry concurrent commands with ncqrs

MF

Marco Franssen /

In a previous post I showed you some pseudo code Gregory Young mentioned in his DDD CQRS course I attended in Krakow, Poland. In this course Greg made clear to us locking of databases isn't necessary. He showed us some pseudo code how to easily write a merge handler to handle all concurrency conflicts. In my current project, based on the ncqrs-framework I implemented a simpler version of this merge handler which only retries each command if a ConcurrencyException occurs. To achieve this you can…

Cover Image for Install and boot Windows 8 from vhd

Install and boot Windows 8 from vhd

MF

Marco Franssen /

In a previous blog post I explained to you how to install Windows 8 in a virtual machine in VirtualBox. In VirtualBox I used 1GB of memory and 2 of my cores and it performed quite good. However in the metro interface I had some issues with my mouse (scrolling, delays etc.) So yesterday I decided to install Windows 8 on a vhd and boot directly from it. To do so I followed Scott Hanselman's blog post. Below I placed a shorter summary for you guys: Step 0 Make sure you have at least 40GB of free…