Polluted Global Namespace

A few years ago it was only Internet Explorer that polluted the JavaScript global namespace with creating all its own generally unwanted global variables referencing everything in your web page that has a name or id. Unfortunately some other browsers have decided to duplicate this IE bug and now also pollute the global namespace with variables for each id in the page. Of all the major browsers in common use today all of them have now made JavaScript slightly harder for beginners to use by duplicating this bug. The only major browser that doesn't always duplicate it is Firefox where it only has the bug in web pages that use quirks mode and doesn't pollute the global namespace with these unwanted variables if you actually use a doctype with your page. The less popular browsers may or may not have duplicated this bug.

The one thing you can be certain of with regard to this particular bug is that there will be browsers out there that do not have the bug and which therefore will process the code correctly in accordance with the standards. If you define your HTML properly in accordance with the standards then Firefox does not display the buggy behaviour. This means that there are no circumstances where you ought to even consider making use of the bug rather than using getElementById to access the element in the HTML properly - simply because the bug doesn't always work and since it isn't a part of the standards and can cause no end of problems the browsers will hopefully fix it before too long.

The problem is that this bug makes it more difficult to write JavaScript properly without these extraneous variables causing problems. At least that's the effect that it has for beginners who haven't learnt how to write their JavaScript properly in an unobtrusive manner since writing your JavaScript to be unobtrusive corrects for this particular bug as a side effect of the way that you write the code.

To see how this works let's consider that we have an id in our web page called 'test'. Let's also assume that we have used the correct HTML 4 doctype at the top of our page and have confirmed that our HTML is valid - since errors in the HTML are a common cause of JavaScript not working properly. This means that Internet Explorer and some of the other major browsers have automatically created a global variable for you called 'text' that references the corresponding element in the HTML that has that id. We know that Firefox (and probably lots of minor browsers) have not polluted the global namespace with that variable and that therefore the variable cannot be used to access the HTML as it doesn't exist in all browsers. The only effect the variable has is to potentially interfere with badly written JavaScript that relies on variables in the global namespace - such as if we wanted to create a JavaScript object to interact with that element in the HTML and tried to name the object with the most appropriate name to identify the element that it interacts with - that name already having been claimed forcing us to select a less meaningful name. So the badly written JavaScript ends up even worse than intended due to the polluted namespace.

Unobtrusive JavaScript doesn't use the global namespace. Instead it creates its own namespace for the specific script so as to keep the content of the script entirely separate from any other scripts that you might want to add to the page. By defining all of the variables that our script needs as local to an anonymous function it no longer matters whether the browser has the bug that pollutes the global namespace or not as we are not using that namespace. If we want to use 'test' as the name of a variable or object within our script we define that name as local to our anonymous function and then we can use the name for what we want without it mattering whether a global variable by that name exists or not.

Our code to do this is:

(function() {
"use strict";
var test;
// rest of script goes here
})();

Having wrapped our script content like that we no longer care whether 'test' is defined globally or not as we have defined our own variable by that name which we can use for whatever purpose we want to use it for. We can even use it for the same purpose that some browsers have defined that global variable for - to provide access to the element in the HTML with that id simply by using:

test = document.getElementById('test');

The difference is that this works in all browsers and complies with the JavaScript standards.

The way that Firefox has implemented this at least makes some sense. The bug first appeared in IE4 and IE5 and so web pages written specifically for those browsers often used this way of accessing the HTML - particularly since IE4 didn't support getElementById. When Microsoft rushed to incorporate CSS 2 into IE5 before the standard was finished and then had parts of the standard change after IE5 came out there were also lots of web pages written using the draft version of CSS 2 that IE5 supported as well. This meant that when Microsoft released IE6 they needed a way to tell whether the pages used the IE5 version of CSS 2 or the standard version and since most pages for IE5 didn't include the doctype while pages written to follow the standards did they used this as the switch for which version of CSS 2 to use. Unfortunately they didn't also use it as a switch for whether to continue to pollute the JavaScript global namespace with these unnecessary variables. Realising that old pages written for IE4 and 5 used these non standard variables Firefox has implemented support for them where the page has no doctype but in order to not pollute pages that follow the standards it does not create those variables when the page has a doctype. Unfortunately other browsers such as Opera and Chrome have also implemented this bug but have stupidly implemented it so that the global namespace is always polluted rather than only doing so when displaying web pages originally intended for IE5 and earlier.

Fortunately the code that we add to make our JavaScript unobtrusive goes a long way toward fixing the problem. Wrapping our code inside an anonymous function and writing strict JavaScript fixes the problem for us just as long as we remember to define the variable within the function if we are going to use it. There is still the problem that if you forget to define the variable as local that the global variable will get used if the browser defines it but at least we have a better chance of detecting when that problem occurs as the script will refuse to run at all in browsers that both support strict mode and which do not pollute the global namespace - thus making it more likely that we will spot the error sooner.

 

This article written by Stephen Chapman, Felgall Pty Ltd.

go to top

FaceBook Follow
Twitter Follow
Donate