Creating a URL Scope in Javascript

Creating a URL Scope in Javascript


A Little Background

I am involved in a project with a major airline, which has allowed me to devote the majority of my coding effort to Front-End (HTML/CSS/JS) development. This position has really allowed me to hone my Javascript skills and it's been a lot of fun to dive into best practices — I'm a nerd and I love it.

However, as a ColdFusion developer, I've missed some of the functionality that CF has built-in. There's a great project out there for CF developers called CFJS, which mimics CF functionality in JS. You should really check out, but this project doesn't include something very useful: The URL scope.

The Problem

What's the best way to access URL parameters in Javascript?

CF has the URL scope, which is something always took for granted. But JS doesn't have this concept, so what can we do to solve this?

The Solution

In order to mimic the URL scope concept from CF, I created a tiny little function in Javascript to parse a URL and provide us with a URL scope.

* Note: This solution is definitely not limited to CF developers. I think it's very useful for all JS developers.

Do a Google search for "javascript url query" and you'll most likely find a function like this:

 
function gup(name) {
    name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
    var regexS = "[\\?&]" + name + "=([^&#]*)";
    var regex = new RegExp(regexS);
    var results = regex.exec(window.location.href);
    if (results == null) return "";
    else return results[1];
}
 

So, for example, if you have this URL:

http://blog.robobrien.com/?bob=123&frank=321&tom=213#top

You would get the value of "frank" like this:

 
/* Get value */
alert(gup('frank'));
 
/* Test for existence */
if (gup('frank') != '') {
	alert('Frank is alive! ' + gup('frank'));
}
 

It's popular. It works. It's dandy. But, can we make it better? I don't like that it re-parses the URL every time we call "gup()", I don't like that we have to test for an empty string to determine a parameter's existence (what if it exists, but is blank?), and I don't like that it uses RegExp (who can read that?!)

Here's the solution I created and have used in multiple projects:

 
(function(location) {
	var url = window.url = {},
		query = location.search.substr(1),
		arrParams = [],
		param = '';
		len = 0,
		i = 0;
	url._location = location;
 
	arrParams = query.split("&");
	len = arrParams.length
	for (i=0; i<len; i++) {
		param = arrParams[i].split("=");
		url[param[0]] = unescape(param[1]);
	}
})(window.location);
 

Bam! We're done. Errr... wait, what?

Rather than just saying, "Here's a function. Use it!" Let's dig a little deeper...

First, I want to tackle the structure of the function. It may look a little odd at first, but it makes our lives better. This is an anonymous, self-executing function. That means it does not have a name assigned to it and it will execute itself as soon as it's loaded. There are two reasons I do this.

  1. I only need to run the function once (which is also a performance boost over gup), so there's no need to name it and add a variable to the global namespace.
  2. It helps with minification.

Next, let's talk about the "var" declaration. This ensures that all of our variables are local to the function. This means they're not available outside of the function and, more importantly, we don't have to worry about outside variables conflicting with our local variables. This will also help with minification.

Finally, the meat of our function: Parsing the URL. Every major browser supports the Javascript's Location Object. It contains information about the current URL for your page. So, we pass "window.location" into our function and start tearing it apart.

The first thing we do is save the Location Object to a new variable, "url._location". This is done for no other reason than convenience. Since all of our parsed data will live in the "window.url" object, let's make the rest of it available here, too.

Then, we split the query string into pieces (an array) and loop over them to create dynamically named name-value pairs within the "url" object. By doing this, we make the URL params into native JS variables for easy access. That's all there is to it.

So, take our earlier example URL:

http://blog.robobrien.com/?bob=123&frank=321&tom=213#top

After using our new function, we can reference the URL variables more elegantly:

 
/* Get value */
alert(url.frank); 
 
/* Test for existence */
if ('frank' in url) {
	alert('Frank is alive! ' + url.frank);
}
 

If you use a development tool like Firebug (you are, right?), then you can go to your "Script" tab and on the right side, in the "Watch" tab, type in "url" and explore the new object we've created.

Here's a screenshot:

On Minification

Minification is a monster all its own. I've mentioned it a few times in this article, so I want to address it quickly, but I won't go into detail.

First, what is minification? You would have to be under a rock or brand new to JS if you haven't heard of it. It's a way to make your code smaller, but still retain its functionality. It's an important concept in website performance. Read its Wikipedia article for more info.

I write all of my JS in a way that will (hopefully) maximize the benefits of minifcation. Not only will you boost your site's performance, but the process of writing minifiable (that can't be a real word...?) code will help you write better, more solid code.

I use Google's online Closure Compiler to minify my code. I definitely minify all of my code before using it on a production website, but I also minify it as I develop, too. This way, I can see the effects of minification and tweak my code to squeeze more bytes out of my scripts.

Our new function, for example, minifies down to this:

 
(function(c){var d=window.url={},e=c.search.substr(1),a=[],b="";i=len=0;d._location=c;a=e.split("&");len=a.length;for(i=0;i<len;i++){b=a[i].split("=");d[b[0]]=unescape(b[1])}})(window.location);
 

The original code is 325 bytes and is now 196 bytes. That's nearly a 40% savings. Granted, it may not seem like much at this small scale, but it will definitely add up over the life of a project and a lot more JS.

Hopefully that gets you off on the right foot. I look forward to your comments.

UPDATE: Changed document.location to window.location throughout the article. Thanks, Michel.

About the Author

Rob has been in web development for over 10 years, 9 of which have been focused on being a ColdFusion Application Developer. Project Management, eCommerce Consulting, and Marketing Consulting are also in the quiver. If you like what I have to say, consider following me on Twitter or reading more about me here: About Rob O'Brien