In this post, I’ll be discussing patterns and approaches for namespacing in JavaScript.
What is namespacing?
In many programming languages, namespacing is a technique employed to avoid collisions with other objects or variables in the global namespace. They’re also extremely useful for helping organize blocks of functionality in your application into easily manageable groups that can be uniquely identified.
Whilst JavaScript doesn’t really have built-in support for namespaces like other languages, it does have objects and closures which can be used to achieve a similar effect.
Automating nested namespacing
As you’re probably aware, a nested namespace provides an organized hierarchy of structures in an application and an example of such a namespace could be the following: application.utilities.drawing.canvas.2d. In JavaScript the equivalent of this definition using the object literal pattern would be:
var application = { utilities:{ drawing:{ canvas:{ 2d:{ /*...*/ } } } } };
Wow, that’s ugly.
One of the obvious challenges with this pattern is that each additional depth you wish to create requires yet another object to be defined as a child of some parent in your top-level namespace. This can become particularly laborious when multiple depths are required as your application increases in complexity.
How can this problem be better solved? In JavaScript Patterns, Stoyan Stefanov presents a very-clever approach for automatically defining nested namespaces under an existing global variable using a convenience method that takes a single string argument for a nest, parses this and automatically populates your base namespace with the objects required.
The method he suggests using is the following, which I’ve updated it to be a generic function for easier re-use with multiple namespaces:
// top-level namespace being assigned an object literal var myApp = myApp || {}; // a convenience function for parsing string namespaces and // automatically generating nested namespaces function extend( ns, ns_string ) { var parts = ns_string.split('.'), parent = ns, pl, i; if (parts[0] == "myApp") { parts = parts.slice(1); } pl = parts.length; for (i = 0; i < pl; i++) { //create a property if it doesnt exist if (typeof parent[parts[i]] == 'undefined') { parent[parts[i]] = {}; } parent = parent[parts[i]]; } return parent; } // sample usage: // extend myApp with a deeply nested namespace var mod = extend(myApp, 'myApp.modules.module2'); // the correct object with nested depths is output console.log(mod); // minor test to check the instance of mod can also // be used outside of the myApp namesapce as a clone // that includes the extensions console.log(mod == myApp.modules.module2); //true // further demonstration of easier nested namespace // assignment using extend extend(myApp, 'moduleA.moduleB.moduleC.moduleD'); extend(myApp, 'longer.version.looks.like.this'); console.log(myApp);
Web inspector output:
Note how where one would previously have had to explicitly declare the various nests for their namespace as objects, this can now be easily achieved using a single, cleaner line of code.
Dependency declaration pattern
In this section we’re going to take a look at a minor augmentation to the nested namespacing pattern you may be used to seeing in some applications.
// common approach to accessing nested namespaces myApp.utilities.math.fibonacci(25); myApp.utilities.math.sin(56); myApp.utilities.drawing.plot(98,50,60); // with local/cached references Var utils = myApp.utilities, maths = utils.math, drawing = utils.drawing; // easier to access the namespace maths.fibonacci(25); maths.sin(56); drawing.plot(98, 50,60); // note that the above is particularly performant when // compared to hundreds or thousands of calls to nested // namespaces vs. a local reference to the namespace
Working with a local variable here is almost always faster than working with a top-level global (eg.myApp). It’s also both more convenient and more performant than accessing nested properties/sub-namespaces on every subsequent line and can improve readability in more complex applications.
Nested namespacing
An extension of the object literal pattern is nested namespacing. It’s another common pattern used that offers a lower risk of collision due to the fact that even if a namespace already exists, it’s unlikely the same nested children do.
A sample implementation of nested namespacing may look like this:
var myApp = myApp || {}; // perform a similar existence check when defining nested // children myApp.routers = myApp.routers || {}; myApp.model = myApp.model || {}; myApp.model.special = myApp.model.special || {}; // nested namespaces can be as complex as required: // myApp.utilities.charting.html5.plotGraph(/*..*/); // myApp.modules.financePlanner.getSummary(); // myApp.services.social.facebook.realtimeStream.getLatest();
You can also opt to declare new nested namespaces/properties as indexed properties as follows:
myApp["routers"] = myApp["routers"] || {}; myApp["models"] = myApp["models"] || {}; myApp["controllers"] = myApp["controllers"] || {};
Immediately-invoked Function Expressions (IIFE)s
An IIFE is effectively an unnamed function which is immediately invoked after it’s been defined. In JavaScript, because both variables and functions explicitly defined within such a context may only be accessed inside of it, function invocation provides an easy means to achieving privacy.
This is one of the many reasons why IIFEs are a popular approach to encapsulating application logic to protect it from the global namespace.
var namespace = namespace || {}; // here a namespace object is passed as a function // parameter, where we assign public methods and // properties to it (function( o ){ o.foo = "foo"; o.bar = function(){ return "bar"; }; })(namespace); console.log(namespace);
Extensibility is of course key to any scalable namespacing pattern and IIFEs can be used to achieve this quite easily. In the below example, our ‘namespace’ is once again passed as an argument to our anonymous function and is then extended (or decorated) with further functionality:
// let's extend the namespace with new functionality (function( namespace, undefined ){ // public method namespace.sayGoodbye = function(){ console.log(namespace.foo); console.log(namespace.bar); speak('goodbye'); } })( window.namespace = window.namespace || {});
Namespace injection
Namespace injection is another variation on the IIFE where we ‘inject’ the methods and properties for a specific namespace from within a function wrapper using this as a namespace proxy. The benefit this pattern offers is easy application of functional behaviour to multiple objects or namespaces and can come in useful when applying a set of base methods to be built on later (eg. getters and setters).
var myApp = myApp || {}; myApp.utils = {}; (function() { var val = 5; this.getValue = function() { return val; }; this.setValue = function(newVal) { val = newVal; } // also introduce a new sub-namespace this.tools = {}; }).apply(myApp.utils); // inject new behaviour into the tools namespace // which we defined via the utilities module (function(){ this.diagnose = function(){ return 'diagnosis'; } }).apply(myApp.utils.tools); // note, this same approach to extension could be applied // to a regular IIFE, by just passing in the context as // an argument and modifying the context rather than just // 'this' // testing console.log(myApp); //the now populated namespace console.log(myApp.utils.getValue()); // test get myApp.utils.setValue(25); // test set console.log(myApp.utils.getValue()); console.log(myApp.utils.tools.diagnose());
This pattern can feel a lot more like a module creator:
// define a namespace we can use later var ns = ns || {}, ns2 = ns2 || {}; // the module/namespace creator var creator = function(val){ var val = val || 0; this.next = function(){ return val++ }; this.reset = function(){ val = 0; } } creator.call(ns); // ns.next, ns.reset now exist creator.call(ns2, 5000); // ns2 contains the same methods // but has an overridden value for val // of 5000
As mentioned, this type of pattern is useful for assigning a similar base set of functionality to multiple modules or namespaces.
Conclusions
Reviewing the namespace patterns above, the option that I would personally use for most larger applications is nested object namespacing with the object literal pattern.
IIFEs and single global variables may work fine for applications in the small to medium range, however, larger codebases requiring both namespaces and deep sub-namespaces require a succinct solution that promotes readability and scales. I feel this pattern achieves all of these objectives well.