Native JSON in IE8

IEBlog

Internet Explorer Team Blog

Native JSON in IE8

  • Comments 27

As you may have guessed from the title of this post, Internet Explorer 8, as of Beta 2, offers native JSON parsing and serialization. This new native JSON functionality enables Internet Explorer 8 aware AJAX applications to run both faster and safer!

What’s JSON?

For those of you that are not die hard AJAX developers, allow me to provide a bit of background. JSON is a simple human readable data interchange format often used by AJAX applications when transmitting data between the server and the web application.

For example, imagine that you select a contact name from your favorite web mail client so that you can see the contact information. The server might send down a stream of data to the web application (which is running in the browser) that looks like this:

     {
          "firstName"
: "cyra",
           "lastName": "richardson",
           "address": {
                "streetAddress": "1 Microsoft way",
                 "city": "Redmond",
                 "state": "WA",
                 "postalCode":
98052
          },

           "phoneNumbers": [
                "425-777-7777"
                
"206-777-7777"
    
      ]
     }

Fortunately, this format is syntactically compatible with Javascript. Many applications today will use the Javascript eval() function to convert the data payload into a Javascript object. Using eval() is a dangerous and expensive approach. eval() parses the string as a general Jscript expression and executes it. If the string being passed to eval() has been tampered with, it could contain unexpected data or even someone else’s code – which is now injected into your web application.

There are libraries, written in Javascript, that are designed to more safely parse untrusted JSON payloads. Some libraries do a strict verification of the data payload using a parser written in Jscript (http://www.json.org/json_parser.js). Some libraries, like json2.js, do a sanity check on the input string using a regular expression then use the faster eval() for parsing. The ideal solution is a native implementation that protects the application from code injection, is fast and available everywhere.

Native JSON in IE8 Jscript

The Jscript engine for IE8 now has a full native implementation of JSON that significantly improves the speed of serialization, deserialization and improves the overall safety of parsing untrusted payloads while maintaining compliance with JSON support as described in ES3.1 Proposal Working Draft

APIs

We defined a new built-in object ‘JSON’. The object can be modified or overridden. It looks like math or any other intrinsic global object. In addition to the JSON object, special functions, toJSON(), are added to the prototypes of Date, Number, String, boolean objects. The JSON object has two functions: parse() and stringify() .

Example:

var jsObjString = "{\"memberNull\" : null, \"memberNum\" : 3, \"memberStr\" : \"StringJSON\", \"memberBool\" : true , \"memberObj\" : { \"mnum\" : 1, \"mbool\" : false}, \"memberX\" : {}, \"memberArray\" : [33, \"StringTst\",null,{}]";
var jsObjStringParsed = JSON.parse(jsObjString);
var jsObjStringBack = JSON.stringify(jsObjStringParsed);

The object produced by the parse() method and serialized back by stringify() method is the same as:

var jsObjStringParsed =
{
     "memberNull" : null,
     "memberNum" : 3,
     "memberStr" : "StringJSON",
     "memberBool" : true ,
     "memberObj" :
     {
                 "mnum" : 1,
                 "mbool" : false
    },
     "memberX" : {},
     "memberArray" : 
     [
                 33,
                 "StringTst",
                 null,
                 {}
     ]
};

JSON.parse(source, reviver)

The JSON.parse method does the the deserialization. It takes the string in JSON format (specified by the argument source) and produces a JScript object or array.

The optional revive argument is a user defined function used for post parse changes. The resulting object or array is traversed recursively, the reviver function is applied to every member. Each member value is replaced with the value returned by the reviver. If the reviver returns null, the object member is deleted. The traversal and the call on reviver are done in postorder. That’s right; every object is ‘revived´ after all its members are ‘revived”.

The reviver is mainly used to recognize the ISO like strings and transform them in Date objects. As of today, JSON format is not round tripping in Date objects because there is no JScript standard Date literal. ES3.1 draft contains an example of how to make up for this issue using a reviver function.

JSON.stringify(value, replacer, space)

This is the serialization method. It takes the object or the array specified by the value argument and produces a string in JSON format. The value object or array is visited recursively and serialized as specified by the JSON format . If value has a method ‘toJSON()’ then this method acts as a first filter. The original value is replaced by value.toJSON(key) and the resulted value is serialized. The argument key is a string. It is the member name, key, when a object member like (key : value) is serialized. For the root object the key is the empty string.

Date.prototype.toJSON() produces a clean string with no characters to escape. It acts as the de facto serializer because stringify() would return the original string unchanged. Date objects are serialized via toJSON() method.

Number.prototype.toJSON(), String.prototype.toJSON(), Boolean.prototype.toJSON() functions return the ValueOf(). They are intended for correct serialization of objects like “ var num = new Number(3.14);”

The optional replacer argument acts as a filter and it is applied recursively. It could be a function or an array.If the replacer is a function then replacer(key,value) is invoked for each object member key:value . For the root object we call replacer(“”,value). If the replacer is an array, it must be an array of strings. The elements of the array are the names of the members selected for serialization. The order of serialization is the order of the names in the array. An array replacer is ignored when serializing an array.

The optional space argument is about how to format the output text. If it is omitted, the text will be packed without extra whitespace. If it is a number, it specifies the number of spaces to indent at each level. If it is a string (such as '\t' or ' '), it contains the characters used to indent at each level.

How does this affect existing pages?

The ES3.1 proposal for JSON is the form factor used by the popular json2.js. Well, we take over the name JSON. The global JSON object can be overridden. Still, it is not an undefined object anymore. It is the same with introducing new keywords in a language; taking over a name would eventually affect some existing code. The pages that make use of json2.js are unlikely to be affected. With very few exceptions, all these pages will continue to work, only faster.

The pages that define their private implementation of the JSON object could be affected, especially when the private implementation of JSON object is defined by a pattern like “if(!this.JSON) { JSON=…}”. There are two main options to work around this kind of issues:

1. Migrate existing code to use native JSON support

If the private JSON implementation is based on some of version of json2.js the migration should be very simple.

2. Opt out of the native JSON support and continue to use the existing private JSON object

This can be done by renaming or overriding the JSON name. Renaming means to change over all code using the ‘JSON’ name into some different name like ‘MyJSON’. Overriding means to ensure the private JSON definition overrides all code using the native default JSON definition. In most of the cases, just removing the condition “if(!this.JSON)” should do the trick.

Considering the standardization effort in 3.1, using the name ‘JSON’ Is consistent with our desire to be interoperable through well defined interfaces.

There is a lot more about to talk about the native JSON. The parser is not eval() based, it is a standalone implementation. It is the native equivalent of the reference parser provided at JSON support. It is as safe as (http://www.json.org/json_parser.js ) and it is a lot faster. So if you are using eval() or even your own JSON library, consider checking for the native implementation in IE8 to get increased performance and safer operation.

Corneliu Barsan
Senior Developer
JScript team

  • Loading...