The problem
if ( !window.TestClass ) {
function TestClass() {
// ...
}
TestClass.prototype.go = function () {
alert("gone");
};
}
var test = new TestClass();
test.go();
In IEv6, v7 & v8, the above test case fails. This is probably an example of IE’s JScript engine getting ahead of itself: the function “TestClass”, a class constructor here, appears to be defined ahead-of-time (ie. before the
if (...)
is reached), resulting in the
if (...)
test failing and the prototype method not being set. The error then occurs on line 10 because there is no defined method “go”.
The solution
Many of you will probably never encounter the above problem: it only seems to be an issue when the function is defined in the global scope. If defined in a closure (as is common for module patterns), the problem goes away. Example below:
(function () {
if ( !window.TestClass ) {
function TestClass() {
// ...
}
TestClass.prototype.go = function () {
alert("gone");
};
// (Of course, this line is now needed in order to expose
// the class to the global object)
window.TestClass = TestClass;
}
var test = new TestClass();
test.go();
})();
This problem will affect any logic (in the global scope) that defines functions in IE – use of functions as class constructors is just one example. Assuming you use a proper module pattern to encapsulate the code you write, you should not encounter this problem. Gotcha!
Update 27/07/2011
It appears that this problem affects more than just Internet Explorer: further testing in Google Chrome reveals that the following code will create issues:
// You would expect that DOMParser would only be created if it wasn't already defined;
// unfortunately, the function declaration below is always executed, overwriting
// any native implementation. The fix, as mentioned below, is to wrap this code
// in a closure to give it a private scope, then expose the class outside.
if ( !window.DOMParser ) {
function DOMParser() {
// ...
}
}
This is a simplified example (of the job I was solving before in IE, that of emulating the W3C-defined class
DOMParser
), but it demonstrates the problem again. The idea is to define a
DOMParser
class only if one does not already exist (leaving a native implementation alone). Unfortunately, ECMAScript is counter-intuitive in this respect: the class/function
DOMParser
is defined regardless of whether the
if (...)
passes, overwriting Chrome’s own native
DOMParser
class/function.
Once again, the fix is simple: to properly wrap the code in a closure for a module pattern:
(function () {
// Now DOMParser is hidden inside this private scope, stopping it from overwriting
// any native implementation if one exists. Note the need for an additional
// instruction at the end to expose the class/function to the global scope once again.
if ( !window.DOMParser ) {
function DOMParser() {
// ...
}
// See above: expose to global scope
window.DOMParser = DOMParser;
}
})();
About the author
- Dan has spent the past 10 years developing specialist software, using everything from x86 assembly to C++ and VB. For the past few years he has focused on JavaScript development of high-performance virtual machines for the modern web and developing bespoke modern websites using the LAMP stack.
- When he is not working on the next web-based OS, he spends his time out with friends, his girlfriend Jen or planning to buy an American muscle car.

July 27th, 2011
Dan Phillimore
Posted in
Tags: 

