这种新的原生json功能能够使internet explorer 8对现有的ajax应用程序运行得更加快速和安全。
什么是json?
大多数开发者不是只进行ajax程序程序开发的,我这里先介绍一点背景知识。json是一种简单的、人能够阅读的数据交换格式,在ajax程序中,当服务器与web程序之间传输数据时,通常采用这种格式。
举例来说,假如你从收藏的web邮件中选择一个联系人名称,以便能够看到该联系人信息。服务器向web程序(运行在浏览器中)发送的数据流可能是下面的样子:
{
firstname: cyra,
lastname: richardson,
address: {
streetaddress: 1 microsoft way,
city: redmond,
state: wa,
postalcode: 98052
},
phonenumbers: [
425-777-7777,
206-777-7777
]
}
值得庆幸的是,这种格式与javascript的语法完全兼容。当今的很多程序使用javascript的eval()函数将这种得到的数据转换成 javascript对象。使用eval()是不安全的,并且耗费资源。eval()将这个字符串解析为jscript表达式,并且执行。如果传递给 eval()的字符串被篡改过,它就可能含有我们不期望的数据,甚至是别人的代码,这样就注入到了你的web程序中。
现在,有很多采用 javascript编写的库,用来更加安全地解析不受信任的json数据。有些使用jscript编写的解析器(http: //www.json.org/json_parser.js)对数据进行了严格的验证,有些库,像json2,js(http: //www.json.org/json2.js),采用正则表达式对输入的字符串进行全面的检查,然后使用eval()快速解析。理想的解决方案是一种原生实现方法,避免应用程序遭受代码注入,运行很快,并且随处都能使用。
ie8 jscript中原生json
ie8 的jscript引擎已经有了json完全的原生实现,在保持与es3.1提案草案(proposal working draft,地址http://wiki.ecmascript.org/doku.php?id=es3.1: es3.1_proposal_working_draft)中所描述的json支持的兼容性的同时,极大地提高了序列化、反序列化的速度,并且提高解析不信任数据的安全性。
api
我们定义了一个新的内置对象“json”,这个对象可被修改或者重写。看上去很像math或者其他内置的全局对象。除了json对象之外,tojson()这些特定的函数也添加到了date、number、string和 boolean对象的原型上。json对象有两个方法:parse()和stringify()。
例如:
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);
这个由parse()方法产生、又通过stringify()方法序列化回去的对象与下面的对象是完全一样的:
var jsobjstringparsed =
{
membernull : null,
membernum : 3,
memberstr : stringjson,
memberbool : true ,
memberobj :
{
mnum : 1,
mbool : false
},
memberx : {},
memberarray :
[
33,
stringtst,
null,
{}
]
};
json.parse(source, reviver)
json.parse方法执行反序列化,它采用json格式的字符串(由参数source指定),产生jscript对象或者数组。
可选参数revive是一个用户自定义函数,用来计入解析的变化。结果对象或者数组递归遍历,reviver函数用在每一个成员上,每个成员值被 reviver的返回值所替代。如果reviver返回null,则对象成员被删除。对reviver的遍历和调用是按后序遍历完成的。也就是说:对象的所有成员被“revived”之后,整个对象也就“revived”了。
reviver主要用来识别类似iso这样的字符串,将它们转成 date对象。到目前为止,json格式(http://www.json.org/)对date对象来说,是不能来回转换的,这是因为没有 jscript的标准date文字量。es3.1草案(http://wiki.ecmascript.org/doku.php?id=es3.1: es3.1_proposal_working_draft)包含了一个如何使用reviver函数解决这个问题的例子。
json.stringify(value, replacer, space)
这个是序列化方法。它以由value参数指定的对象或者数组为参数,生成json格式的字符串。对象或者数组递归访问,序列化成特定的json格式。如果 value参数有tojson()方法,那么这个方法就起第一个过滤器的作用,原始的value被value.tojson(key)替代,最终的值被序列化。参数key是一个字符串,当类似(key:value)这样的对象被序列化时,key是成员的名字。对根对象来说,key是空字符串。
date.prototype.tojson()生成一个无需转义的字符串,是真正的序列化器,因为stringify()会返回最原始、没有任何变化的字符串。date对象通过tojson()方法进行序列化。
number.prototype.tojson ()、string.prototype.tojson()、 boolean.prototype.tojson()函数返回valueof()。他们用来进行对象的正确序列化,像“ var num = new number(3.14);”这样的对象。
可选的replacer参数起过滤器的作用,递归使用。它可以是个函数,也可以是个数组。如果 replacer是一个函数,那么对每个对象成员key:value都调用replacer(key,value)。至于根对象,调用replacer (,value)。如果replacer是个数组,则必须是个数组字符串。数组的元素就是要进行序列化成员的名字。序列化的顺序按照数组中的名字顺序。在序列化数组时,数组replacer是被忽略的。
可选的参数space是关于如何格式化输出文字的,如果该参数省略,则输出文字没有任何额外的空格。如果它是一个数字,它指定的是每个级别缩进的空格数。如果它是一个字符(比如\t或者“ ”),它就以这些字符缩进每一个级别的字符。
对现有的网页有何影响?
es3.1 json提案是被流行的json2.js所使用的主要因素。我们也采用json这个名字。全局对象json能够被重写。然而,它不再是一个未定义的对象。这与通过在脚本语言中引入new关键字是相同的。采用一个名字偶尔会影响现有的代码。使用json2.js的页面不太可能会受影响。除了极少数的例外,所有这些页面都将会继续正常工作,只能是运行得更快。
那些自己实现的json对象定义的页面可能会受到影响,尤其是使用类似“if(!this.json) { json=…}”这种模式定义的json对象。有两种主要的方法可以解决这个问题:
1,将现有代码迁移,使用原生json对象
如果自己的json实现是基于json2.js的某种版本的,迁移起来就很简单。
2,决定不使用原生json支持,继续使用自己现有的json对象
这可以通过重命名或者重写json名字实现。重命名意味着要将所有使用json名字的代码修改成类似“myjson”这样的名字。重写意味着确保自己的 json定义重写所有使用默认原生json定义的代码。大多数情况下,只需移除条件“if(!this.json)”就可以了。
考虑到3.1标准的影响,使用json这个名字与我们通过定义好的接口进行互操作的愿望是一致的。
关于原生json,要谈论的事情还有很多。解析器不是基于eval() 的,是一个独立的实现。它与json支持(http://wiki.ecmascript.org/doku.php?id=es3.1: json_support)提供的引用解析器是等同的。它也是和http://www.json.org/json_parser.js一样安全的,并且运行速度要快很多。所以,如果你使用eval(),或自己的json库,请检查一下ie8中原生json实现,以便得到更好的性能和更安全的操作。