How Internet Explorer 8 document mode affects JavaScript

In a previous post, I talked about Internet Explorer 8′s wide array of browser and document modes. Most people are pretty familiar with how the various document modes affect layout in terms of how CSS is implemented, but what has been lost is how the document mode affects the core JavaScript engine in the browser. These changes are somewhat subtle, but important to understand when you’re working with Internet Explorer 8.

A couple of years ago, Microsoft published a paper called, JScript Deviations from ES3, in which they outlined ways in which the JScript engine (the one power Internet Explorer’s JavaScript) had deviated from the ECMAScript 3 standard. These deviations are somewhat innocuous, but chances are that you’ve been bitten by one or more of them at some point in the past. In Microsoft’s attempt to make Internet Explorer 8 more standards-compliant, the same issues that arose around CSS also arose around JavaScript. They could fix the deviations in JScript, but if the browser were running in IE5 or IE7 document modes, there could be problems as these fixes might be incompatible with the code targeting those browsers.

Microsoft chose to create versioned features of the JScript engine for Internet Explorer 8. For IE5 and IE7 document modes, the JScript engine acts as it did in the actual Internet Explorer 7, complete with all deviations from ECMAScript 3. When in IE8 document mode, the deviations are gone and you get the full power of the JScript engine.

Native JSON

Internet Explorer 8′s JScript engine implements the native JSON object object as defined by ECMAScript 5. The object is only present, however, when the page is running in IE8 document mode. This includes the global JSON object as well as methods used for JSON functionality:

  • Date.prototype.toJSON()
  • Number.prototype.toJSON()
  • String.prototype.toJSON()
  • Boolean.prototype.toJSON()

The JSON object and these methods in IE5 or IE7 document mode are undefined.

Note: Even though Date.prototype.toJSON() is supported in IE8 document, Date.prototype.toISOString() is not implemented. This is strange because they return the same value.

DOM getters/setters

One of the more curious aspects of the JScript engine is that it implements ECMAScript 5 getters and setters, but only for DOM objects and not for native JavaScript objects. The implementation is made up of half-baked versions of Object.defineProperty() and Object.getOwnPropertyDescriptor() that primarily support the get and set properties. For example:

Object.defineProperty(document.body, "active", {
    set: function(value){
        document.body.className = (value !== false) ? "active" : "";
    },

    get: function(){
        return document.body.className == "active";
    }

});

var descriptor = Object.getOwnPropertyDescriptor(document.body, "innerHTML");
alert(descriptor.get);   //displays function

Both methods are only available in IE8 document mode and do not exist in other document modes.

Arrays

One of the areas where the JScript implementation really fell apart was in dealing with arrays. Arrays had the most deviations from the ECMAScript 3 standard and were a constant source of headaches for developers. First, if undefined is passed into join(), the argument was translated into the string “undefined” and that was used to concatenate the items. For example:

var colors = ["red", "green", "blue"];
alert(colors.join(undefined));    //"redundefinedgreenundefinedblue" in IE7

When running in IE8 document mode, a value of undefined is ignored and the default separator (a comma) is used.

The unshift() method, which pushes an item to the front of the array, also had a deviation in JScript. Instead of returning the length of the array after adding the item, it simply returned undefined. In IE8 document mode, this has been fixed so that unshift() correctly returns the array length.

The last big change to arrays is the ability to properly inherit from the Array type. Dean Edwards has a whole post about trying to create a subtype of Array and the problems he encountered. The biggest problem is that assigning an instance of Array to be another constructor’s prototype meant that the length property would no longer work. Consider the following:

function MyArray(){
}

MyArray.prototype = new Array();
MyArray.prototype.get = function(i){
    return this[i];
};

var colors = new MyArray();
colors.push("red");
colors.push("green");
colors.sort();
alert(colors.get(0));    //"green"
alert(colors.length);    //in IE7, outputs "0"; in IE8, outputs "2"

In Internet Explorer prior to 8, the length property of any Array type descendant didn’t change automatically, and so inheritance was only truly useful only for non-IE browsers. In IE8 document mode, though, the length property works as it does in other browsers while IE5 and IE7 document modes use the old deviated behavior.

Miscellaneous fixes

There’s a small group of fixes that can’t really be logically categorized but nonetheless help JScript come more into agreement with other JavaScript implementations. The first is that object literals now allow trailing commas. Prior to Internet Explorer 8, the following would cause a parse error:

var object = {
    name: "value",
};

The trailing comma after the last property value is explicitly allowed by ECMAScript 3 syntax and is allowed in all other browsers. IE8 document mode now also supports this syntax correctly (other document modes still throw the error).

Another nice enhancement is that IE8 document mode now allows access to characters in a string via bracket notation:

var s = "Hello world!";
alert(s[0]);    //"H"

This brings JScript into line with other JavaScript engines; IE5 and IE7 document modes will still return undefined.

Two other changes that likely don’t affect you but are worth noting:

  • Number.prototype.toPrecision() used to throw an error when undefined was passed in. IE8 document mode now defaults to calling Number.prototype.toString() in this case.
  • Error.prototype.toString() has been properly implemented to provide better error messages.

Conclusion

IE8 document mode offers a whole host of improvements over Internet Explorer 7 not just in CSS but also in JavaScript. If you’re looking to write the most standards-compliant code possible, make sure your page is being run on Internet Explorer 8 in IE8 document mode (see my previous post for details). Bringing JScript into line with other JavaScript engines is an incredibly important step. It’s too bad that these details were pretty much overlooked in the Internet Explorer 8 announcements.

Comments

  1. Luke Smith

    Technically only Date.prototype.toJSON is defined in the ES5 spec. IE8 implemented native JSON (quite well, considering) while the spec was in draft and included the others. Only Data.proto.toJSON is required for the functionality.

    Likely the reason for the half baked Object.define* and missing getters/setters and Date.proto.toISOString is that either they were not in the draft spec at the time, or the final API was in such contention that it was a safer option to avoid implementation.

  2. Nicholas C. Zakas

    @Luke In the final ES5 spec, section 15.9.5.43 defines Date.prototype.toISOString() and I think it's been there for a while. I thought it was explicitly included as part of JSON support (but who knows?). I didn't realize that Date.prototype.toJSON() was the only one included in ES5. Yay IE for over-doing it. :)

  3. Luke Smith

    Yep, I see Date.prototype.toISOString in the initial draft spec from May 2008[1]. Of course, IE8 beta1 was delivered in March 2008[2] before even that first draft, so who knows how much attention was given to such issues (over, say, crasher bugs) beyond that point. And the various toJSON methods weren't pulled until very near the final draft.

    [1] http://wiki.ecmascript.org/...
    [2] http://en.wikipedia.org/wik...

  4. Allan Ebdrup

    I've had to use IE7 compatability on my JavaScript heavy spare time project http://obsurvey.com because the implementation of contenteditable divs in IE8 mode is buggy, the layout does not flow correctly. So even though IE8 follows the standards more, the features you describe is not something I use, and having a site that works is more important. I'm beeing practical. I wonder what I'll do when IE9 arrives?

    On a side note I guess you could answer this,I've been able to gather that people try to avoid "new" in JavaScript, I've never been able to figure out why, I don't have any problems with it. Could you point to an article that can enlighten me?

Understanding JavaScript Promises E-book Cover

Demystify JavaScript promises with the e-book that explains not just concepts, but also real-world uses of promises.

Download the Free E-book!

The community edition of Understanding JavaScript Promises is a free download that arrives in minutes.