Random thoughts & observations

From the mundane to the profound and everything in between here’s what’s rocking our world

JavaScript namespacing and modules

Posted: September 12, 2015
Written by: Saints At Play
Category: Javascript

As JavaScript has, at the current time of writing, no native support for namespaces we, as developers, have to implement our own approaches/solutions to avoid polluting the global namespace with objects/methods and variables that might conflict with/overwrite one another if we are not careful.

In this article we take you through using namespaces and modules to better manage your code.

What are namespaces?

In programming languages a namespace is a way to collect, group and organise items (such as objects, methods and variables) so that name collisions can be avoided. A name collision occurs when the same variable/method name is used from two separate contexts that are then brought together. This might occur, for example, if 2 custom scripts separately contain a function titled with the same name that, when concatenated together (or where both scripts are called onto the same HTML page), conflict with and overwrite one another.

As such a scenario would introduce bugs into our code namespaces are an approach that helps to avoid such naming collisions from occurring.

In JavaScript we can implement a namespace as follows:

// Associate MYNS global variable with MYNS namespace (so we don't overwrite 
// an existing object)
// Or create a new object if the MYNS object doesn't exist
var MYNS        = MYNS || {};


// Attach a method to the MYNS namespace
MYNS.methodName = function()
{
   // Some code here
};

The above example implements a namespace via a single global object (the MYNS variable) for our application. All functions/variables that are attached to that namespace then become properties of the MYNS global object.

This is all good and well but we can start to run into problems with complex applications that require multiple types of related functionality to be implemented.

This is where modules come into play.

Namespacing and modules

By grouping related functionality into their own specific modules (such as, for example network related, DOM parsing, AJAX management etc) we can extend our global namespace object for more effective organisation and management of our code:

// Our global object namespace
var MYNS              = MYNS || {};


// Create an object container for all our namespace modules
MYNS.Modules          = {};


// Now create the ajax, dom and network modules
MYNS.Modules.Ajax     = {};
MYNS.Modules.Dom      = {};
MYNS.Modules.Network  = {};

The above could also be written as an object literal:

var MYNS      = MYNS || {
   Modules    : {
      Ajax    : {
         // Methods
      },
      Dom     : {
         // Methods
      },
      Network : {
         // Methods
      }      
   }
};

Developing from the above examples we can then start to implement our methods for each module without worrying about whether or not the naming of these methods might already be used elsewhere within our namespace.

Namespace generation and handling

The above approaches to generating namespace modules can become hard to maintain over time and prone to potential errors such as assuming that a certain namespace or property exists. One way of overcoming this is by using a namespacing function like the following (based on an existing example by Stoyan Stefanov in the excellent JavaScript Patterns book):

MYNS.namespace = function(ns)
{
  var segments = ns.split('.),
      parent   = MYNS,
      counter;

  if(segments[0] === 'MYNS')
  {
    segments   = segments.slice(1);
  }

  for(counter = 0; counter < segments.length; counter++)
  {
    if(typeof parent[segments[counter]] === 'undefined')
    {
      parent[segments[counter]] = {};
    }
    parent     = parent[segments[counter]];
  }
  return parent;
};

The above function, which won't recreate the namespace if it already exists, can be implemented to generate new modules like so:

// Generate 2 new modules for the MYNS namespace
var Helpers     = MYNS.namespace('MYNS.Modules.Helpers'),
    Validation  = MYNS.namespace('MYNS.Modules.Validation');

Declaring your modules

As developers we should, as far as is possible, be aware of and implement best practice considerations to make our code perform faster, be more manageable and allow for scalability.

With namespaces and modules we can specifically accomplish this by declaring our dependencies upfront in our functions/scripts like so:

function someNameHere()
{
   var ajax        = MYNS.Modules.Ajax,
       dom         = MYNS.Modules.Dom,
       network     = MYNS.Modules.Network;
       
};

The benefits of declaring our modules/dependencies up front at the beginning of our scripts/functions are as follows:

  • The global variable lookup (I.e. MYNS.Module.Ajax) is performed only once after which the local variable is used leading to faster performance (due to not having to repeatedly look up the nested properties of an object such as MYNS.Modules.Dom)
  • Makes it to easier to see what scripts files are required to be included in the page
  • Makes it easier to resolve dependencies instead of having to hunt through a script to find all instances of where they may be called

Namespace conventions

When implementing namespaces in JavaScript it is accepted convention to capitalise the spelling of the global variable (MYNS - in the above examples).

Be aware though that this is also a convention that is used to denote constants within our scripts (I.e. values that do not - or should not - change through the course of a script's execution):

var PI               = 3.14159,
    CENTURY          = 100,
    SPEED_OF_LIGHT   = 299792458;

In closing

Namespaces provide JavaScript developers with a number of benefits:

  • Helps to avoids name collisions on objects, methods and variables
  • Allows for creation of modules to group and better organise related functionality
  • Allows for nesting of objects (I.e. sub-modules)
  • Implements a standard way of organising/managing code that is universally agreed upon
« Return to Posts

Comments

There are no comments

Posting comments after three months has been disabled.