Click here to Skip to main content
Click here to Skip to main content
Go to top

Writing modular JavaScript without polluting the global namespace

, 12 Mar 2012
Rate this:
Please Sign up or sign in to vote.
How to write 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 bullsh*t, 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 
    }
}());

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));

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.

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 are 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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

marcofranssen
Software Developer Atos
Netherlands Netherlands
I am a .NET Software Developer at Atos International. Architecture, CQRS, DDD, C#, ASP.NET, MVC3, HTML5, Jquery, WP7, WPF, ncqrs, Node.js
Follow on   Twitter   Google+   LinkedIn

Comments and Discussions

 
Questioncheck this out PinmemberSeishin#12-Mar-12 22:20 
QuestionFew criticism PinmemberNikola Radosavljevic12-Mar-12 6:06 
QuestionAlternative perspective on pollution [modified] Pinmemberjsc4212-Mar-12 5:10 
QuestionCouple of typos Pinmemberjsc4212-Mar-12 4:53 
Firstly, a couple of typos. In both code samples, you write
return {
        removeProduct: removeProduct,
        removeProduct: removeProduct
    }
 
but I assume that you mean
return {
        addProduct: addProduct,
        removeProduct: removeProduct
    }
and your code for creating your new namespace is
}(window._jsShop = window._jsShop = {}, window, document));
but should be
}(window._jsShop = window._jsShop || {}, window, document));
 
[Aside: I do not like the technique of missing arguments from function calls and relying on the missing argument taking the undefined value. This is easily broken if the caller accidentally adds a comma. It is safer to add var undefined; at the top of the function body].
Questionlink is broken PinmemberRedAnthrax_9-Mar-12 6:56 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.140922.1 | Last Updated 12 Mar 2012
Article Copyright 2012 by marcofranssen
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid