Your JS is a Mess. Javascript Namespacing

Cover Image for "Your JS is a Mess. Javascript Namespacing"

Developer TrainingWeb Development
Chances are, unless you’re somewhat experienced with Javascript, you probably write a lot of sloppy JS.
It’s not an insult. Don’t take it that way. It’s just a reality, and it’s not your fault.
When everyone starts out with Javascript (like any programming language), they learn how to write it the most basic way. And most of the time with Javascript, that’s enough for you to be pretty productive. For a while.
Once you’ve got a f***ton of JS code on your website though, it’s gonna be harder to maintain, organize, read, or even find what you need. It’ll be more prone to breaking, and harder to debug. And you’ll be hiring someone like me to come clean it up and teach you how to do it better. While I enjoy money, there are some helpful JS techniques that can make your life easier in the meantime.

Enter Javascript Namespacing

Namespaces and encapsulation exist in just about any object-oriented or object-based programming language. They’re simple to understand, and can go a long way in making your code more organized. Learn what I’m about to teach you, make it into a habit, and then come back and thank me for it.

TL;DR:

 Namespacing == good. If you already know why and want to skip to how, jump to How to Namespace Your Javascript below.

Why Namespace Javascript? It’s All About Organization

Ever live with a hoarder? I haven’t, but I’ve lived with messy people. It drove me nuts. Given, I’m more crazy than most when it comes to neatness. But still. Live in an apartment that is a perpetual mess, and you’re guaranteed to be slower at getting anything done. Same deal for a messy desk at work.
If your code is a mess, it’s going to slow you (and other developers) down big time. Sometimes you’ll realize it, sometimes you won’t. It’s the kind of thing where you’re so used to working with the status quo that you don’t know what “better” feels like.
It’s far more noticeable when you’ve got components you want to make reusable. You take the function and put it in a separate file, and something breaks. You make it work, but no one knows where to find it. There’s no logical separation.
Or you have something important and you want to add automated tests to it. But you can’t, because your functions only run on the page you created them on.
But I use CommonJS/AMD. Do I still need to learn this?
Yes. Even though these make your JS more modular by themselves, complex classes will still have a lot of moving parts within them. Namespacing is still very, very useful.
But I use AngularJS/React/whatever. Do I still need to…[*interrupts you*]
YES! Complex code always needs organization. Frameworks use their own namespaces (e.g.,  angular.module() or React.createClass() among tons of examples). Your code, as it gets complex, will need them too.

Where Namespacing Helps

Here are a few examples of the types of code namespacing can make better, and why.
Grouping Loose Methods

namespacing-grouping-methods.js

// Old
function sum($elements) { /* calculate sum */ }

function product($elements) {  /* calculate sum */}

// New
var MathUtils = {
  function sum($elements) {},
  function product($elements) {}
};

Grouping Data

namespacing-grouping-data.js

// Old
var DEBUG = false;
var MAX_ENTRIES = 100;
var FEED_URL = "http://mysite.com/feed/";
var POST_IDS = [123, 456, 789];

// New
var Config = {
  DEBUG: true,
  MAX_ENTRIES: 100,
  FEED_URL: "http://mysite.com/feed/",
  POST_IDS: [123, 456, 789]
};
Encapsulating a UI Component
When an HTML element has a certain behavior and information attached to it, it’s very logical to keep its behavior and data in one place. Here’s an example of a simple select box that gets populated with data, and an event gets attached to it.
Here the data (the countriesIveBeenTo array) is a global variable which can get overwritten. Also this code is heavily tied to the #countries element; there’s no way we can reuse it for multiple select boxes.

namespacing-components-bad.js

// Heavily Coupled
$(function() {
     $(document.body).append( $('<select id="countries"></select>') );

     var countriesIveBeenTo = {
          'BE': 'Belgium',
          'CR': 'Costa Rica',
          'IT': 'Italy',
          'US': 'United States of America',
          'UK': 'United Kingdom'
     };

     $.each(countriesIveBeenTo, function(val, text) {
          $('select#countries').append(
               $('<option value="' + val + '">' + text + '</option>')
          );
     });

     $('select#countries').change(function() {
          console.log('Selected country: ' + $('select#countries :selected').text());
     });

});
But putting this component in its own namespace, we can keep the data inside the component so it can’t be overwritten by a variable with the same name. I’ll go more into detail on this approach in another article. But just know that this keeps our data private, and makes this module far more reusable:

namespacing-components-better.js


// Less Coupled
var CountrySelectClass = function() {
  var countriesIveBeenTo = {
    'BE': 'Belgium',
    'CR': 'Costa Rica',
    'IT': 'Italy',
    'US': 'United States of America',
    'UK': 'United Kingdom'
  };

  this.init = function(selector) {
    this.$el = $(selector);

    $.each(countriesIveBeenTo, function(val, text) {
      this.$el.append(
        $('<option value="' + val + '">' + text + '</option>')
      );
    }.bind(this));

    this.$el.change(function() {
      console.log('Selected country: ' + this.$el.find(':selected').text());
    }.bind(this));
  };
};

$(function() {
  $(document.body).append( $('<select id="countries"></select>') );

  var csInstance = new CountrySelectClass();  
  csInstance.init("#countries");  
});

  
Reducing Conflicts & Data Overwriting
Ever create a Javascript variable called id, or userId, or link or div or element?
I sure have. At least a hundred times apiece. Know what happens when you accidentally create the same variable twice in the page?
Say you’ve got a login form with a big div above it containing any error messages:

namespacing-bad-form-example.js

var element = $("div.form-errors");

if (formHasErrors()) {
  element.show();
}

// More, unrelated code...

var element = $("form#login");
element.addClass("has-errors");

// Another block of code...

$("input.submit").on("click", function() {
  element.remove();
  // ...
});
Guess what? When the user clicks submit, the form field disappears instead of the error container. This could have been avoided if the components were namespaced:

namespacing-better-form-example.js

var LoginFom = {
  element: $("form#login-form"),
  
  hasErrors: function() {
    // validation code here...
    // returns true or false.
  }
};

// ...

var ErrorContainer = {
  element: $("div.form-errors")
};

if (LoginForm.hasErrors()) {
  ErrorContainer.element.show();
}

LoginForm.element.addClass("has-errors");

$("input.submit").on("click", function() {
  ErrorContainer.element.remove();
});

How to Namespace Your Javascript

In their simplest form, Javascript namespaces are just normal Javascript objects.

namespacing-js-object-definition.js

var MyNamespace = {
  myString: "someString",
  myInt: 123,
  myFunc: function() {
    return this.myString + " " + this.myInt;
  }
};
You access them like so:

namespacing-usage.js

MyNamespace.myString;
MyNamespace.myInt;
MyNamespace.myFunc();
You can nest them as deep as you want:

namespacing-usage-nesting.js

var MyCompany = {
  Widgets: {
    data1: 123,
    func1: function() {}
  },
  HtmlUtils: {
    data1: 123,
    func1: function() {}
  }
}

// Usage: 
// MyCompany.Widgets.data1;
// MyCompany.HtmlUtils.func1();
You can build them gradually, rather than in one shot (this helps you separate things into different files):

namespacing-multiple-files.js

// /javascripts/mycompany.js
var MyCompany = {};

// /javascripts/mycompany/widgets
MyCompany.Widgets = {};
MyCompany.Widgets.data1 = 123;
MyCompany.Widgets.func1 = function() {};

// /javascripts/mycompany/htmlutils.js
MyCompany.HtmlUtils = {};
MyCompany.HtmlUtils.data1 = 123;
MyCompany.HtmlUtils.func1 = function() {};

Namespacing with jQuery

If you prefer using a jQuery structure, you can use similar namespacing via the $ object. Using the example above, it’s the same deal:

namespacing-jquery.js

$.MyCompany = {
  Widgets: {
    data1: 123,
    func1: function() {}
  },
  HtmlUtils: {
    data1: 123,
    func1: function() {}
  }
};

// Usage:
// $.MyCompany.Widgets.data1;
// $.MyCompany.HtmlUtils.func1();
I tend to avoid this approach except for functions that follow the jQuery function convention (i.e., working off of DOM elements and returning a jQuery object). My keeping a separate top-level namespace (MyApp or MyCompany), it makes it a lot easier to distinguish your app’s custom code from that of jQuery plugins.

Namespacing Strategies

When looking at a messy JS codebase, I usually try to group things in logical categories. Patterns like this are common:

namespacing-strategy.js

// Top level. All reusable code goes somewhere under this main object.
var MyApp = {};

// Widgets, and any components that manipulate the DOM.
MyApp.UI = {};

// Classes that have reusable logic or calculation.
MyApp.Lib = {};

// Custom code that works with external javascript libraries in a reusable way.
MyApp.Vendor = {};

// Generic utilities.
MyApp.Utils = {};
Every once in a while it makes sense to take another look at everything as a whole and reassess whether the organization makes sense. If it doesn’t, see what might make better sense & do some refactoring.

Namespacing Utilities

For a touch of elegance, for many years I’ve used a utility function I got from Ext.js many years ago. With one line of code, you can easily ensure the namespace you need gets instantly created, no matter how many levels deep:
https://gist.github.com/mcavaliere/865a836c1830c3372e43 Note that this function should be defined with your top-level namespace, before you define anything else.
You use the namespace method like this, inside each module’s file:

namespacing-utilities-usage.js

// /javascripts/myapp/ui/fancyslider.js

MyApp.ns("MyApp.UI.FancySlider");

MyApp.UI.FancySlider = function() {
  // ...
};
Now it will make sure MyApp, UI and FancySlider sub-namespaces all exist; this is super handy in case your Javascript files are included in an order you don’t always control (like with the Ruby on Rails asset pipeline, for example).
That’s my intro to namespacing. Lots of detailed info for a very simple, but powerful concept. Never write code without it.