Monday, April 30, 2012

JavaScript Fun Part 1: Namespacing

JavaScript: That Silly Scripting Language Is Actually Much, Much More


I have been developing in strongly typed languages, mainly C#, for the majority of my career. Although I've been using JavaScript my entire career, at this point, I'd say it would be a stretch to say I've been developing in JavaScript. Most of my career, when I thought of JavaScript I thought, "It's that cute little scripting language I use to manipulate the DOM and make alerts or whatever." Beyond that, I've always thought of JavaScript as something less than a full-fledged programming language.

Over the last several years, thanks to developments like Ajax, JQuery and other libraries like KnockoutJS, I've been forced to delve deeper and deeper into JavaScript, as brunt of UI development has been migrating it's way to the client, rather than just rendering HTML at the server. At first, like I said, I felt "forced" to deal with JavaScript, but as my understanding grew of JavaScript as a language, I've discovered that JavaScript is powerful and actually fun to use, learn and develop in.

Namespacing: Why it's important to JavaScript


One of the things I've seen the most when I'm doing a code review of a friend's JavaScript, or just helping solve a bug is the over use of global variables for variable, object and function declarations. What I mean by "global variables" is simply any function on the "root" or window object. For example:

Example of global declarations.


<script type="text/javascript">
var name = 'Ben Lesh';
function logName() {
    console.log(name);
}
</script>

logName() and the variable "name" are global. So what's the big deal? My code works, why is this so bad? Well, honestly, often this is just fine. But nowadays, web applications are referencing more and more script files, often from third parties. All it would take is for one of those referenced scripts to have a function or object with the same name and you'll start to see defects. Say with our example above, we were also referencing a script file that had a method declaration in it named "name":


<script type="text/javascript">
var name = "Ben Lesh";
function showName() {
    alert(name);
}
</script>
<!-- here is some script reference that is going 
to overwrite our name variable -->
<script src="/name.js" type="text/javascript"></script>

Contents of name.js:

function name() {
  alert('Tom Jelen');
}

Now when we call " showName();" later in our scripts we won't get the expected behavior at all. It will alert a function, rather than the name. Why? Because we overwrote that global variable.

So how do we avoid this? With namespacing!

"But JavaScript doesn't have namespacing like .NET does!"


True enough. JavaScript, as of this writing, does not have a namespace keyword (and probably never will). It does have Java's "package" keyword reserved, but it's not currently used. So how do we accomplish namespacing in JavaScript. Well, what is namespacing? It's a way to organize code!  It turns out that "namespacing" in JavaScript is just a fancy way to say "I'm going to put a bunch of code in a dynamic object for safety's sake." There are a thousand ways to skin this cat in JS, so I'll cover the basic ideas. 

Generally, a "namespace" will be rooted in a global variable. Since you might use the namespace in multiple code files, it's a good idea to declare it with a JavaScript coalesce so the declaration of the namespace in one code file doesn't overwrite a previous declaration, like so:

/* declaration of the namespace. This will need to
* be done before the namespace is extended in every file
* in which the namespace is extended. */
var NS = NS || {};

// add stuff to our namespace
NS.name = 'Ben Lesh';
NS.showName = function () {
  alert(NS.name);
};

Now when another file has a function named "name" declared, you should be all set. The only thing you'd have to watch out for is that no referenced files would have a declaration of the global variable "NS".

No comments:

Post a Comment

This form allows some basic HTML. It will only create links if you wrap the URL in an anchor tag (Sorry, it's the Blogger default)