Just One JavaScript Global Variable? Sorry.

©2011, Martin Rinehart

JavaScript is a marvelous language. I love its flexibility. I love being able to create an object without writing a constructor. I love functions that are first-class objects.

That said, I do not love creating a mess of global variables. I do not love my code competing with your code. You can mitigate these problems by creating a single global variable that will be a namespace for almost everything else in our code. There are two ways to do this.

Wrap Everything in a Function

If you have a small application, the simplest way to create a global namespace is to wrap your code in a function.

function my_unique_name() {

    var foo = ...; // local to my_unique_name()
    function bar() { ... } // also local

} // end of my_unique_name()

my_unique_name() // run your code this way

This method is simple. You can retrofit it to code that didn't have a namespace after the code is working. The only part that requires some thought is choosing a name that will be unique. my_unique_name is self-descriptive, but not well-chosen. Choosing a unique name is like choosing a password: mix uppercase and lowercase and use some digits, too.

Do you see the comment that says // run your code this way? There is another way to run your code that is cryptic, tricky and easy to overlook. Never, not ever, write code that shows how clever you are. Write code that is obvious and not one bit clever.

Wrap Everything in an Object

From the simple way, we now move on to the hard way. The simple way has a major problem: nothing inside the namespace wrapper is accessible from outside the namespace wrapper. There is no simple way to hook an event (such as a button click) to any function inside the namespace. You can get around this by providing "getters" (functions that return references to data and code) but the whole elegant simplicity of the function wrapper is then gone.

The clean solution is to wrap everything in an object, this way:

var my_unique_name = {

    foo: ...,
	// foo is now a property name
    bar: function () { ... }
	 // bar, too


my_unique_name.bar() // run your code this way

You change the variable assignments (foo = value;) to property assignments (foo: value,). The equal signs, =, become colons, : and the semicolons, ;, become commas, ,. Wrapping existing code in a function requires almost no code changes. Wrapping existing code in an object is, at best, a PITA. It's much easier to start in object-wrapper style than to convert.

As a practical matter you will very quickly tire of typing my_unique_name. ad infinitum, ad nauseum. Useful trick: pick something short but unique, like "zxc". (Look at your keyboard.) When you are ready to release your masterpiece to the world, global search/replace zxc with your_well_chosen_unique_name.

Another way to achieve the same effect is this:

var my_unique_name = {};

my_unique_name.foo =  ...;
    // foo is now a property name
my_unique_name.bar = function () { ... }
     // bar, too

// nothing needed to run your code

If you have existing code, you just search/replace foo with my_unique_name.foo, bar with my_unique_name.bar, etc. This is conceptually simpler than the object syntax suggested above but as a practical matter, global search/replace for every variable (including functions) in a non-trivial piece of code is a non-trivial task. You will also, within the code, never again type foo. You must type my_unique_name.foo. (Is bar to be twice foo? In the first style bar: 2 * foo,. In the second style my_unique_name.bar = 2 * my_unique_name.foo.)

Whatever you chose, you are now ready to congratulate yourself on having created a masterpiece that has exactly one global variable. Uh, sorry. This is JavaScript.

Everything? Not Really

Firefox 3.6.13 does not create the globals we're about to discuss. Earlier Firefox versions did. Latest Chrome, MSIE, Opera and Safari still do. Consider this bit of code:

var my_div = document.createElement( 'div' );
    my_div.id = 'div1';

alert( typeof(div1) ) // reports "undefined"

document.body.appendChild( my_div );

alert( typeof(div1) ) // reports "object"!
alert( div1 === document.getElementById( 'div1' );
        // reports "true"

What? Except in the latest Firefox, appending a child to the DOM, if the child has an id, also creates a global variable. The name of the global variable is the value of the element's id. The value of the variable is a reference to the DOM element, the same reference that is returned by document.getElementById(). All those times you typed document.getElementById( 'div1' ) you could have just typed div1. (That no longer works in Firefox. The other browsers may fix this, too.)

OMG. Globals galore. What's a poor coder to do? I recommend using that short prefix as a prefix for your element ids, too. zxc_div1 will expand happily to your_well_chosen_unique_name_div1 when you do the big search/replace. Yes, you'll be polluting the global namespace, but you'll be doing it in a smart way that's likely to avoid name collisions.

If you removeChild(), the browsers that create the global variable correctly delete it, except for MSIE. MSIE sets the variable to type "unknown", which is a type I don't know.

Good luck and happy JavaScripting!

Feedback? I'm MartinRinehart at gmail dot com.

# # #