(年初翻译过Kris Zyp的另一篇介绍dojo/json的文章:
Dojo的内建JSON解析模块,本文相比那篇文章更为详细,着重介绍了新老API的对比,对一些API的特殊用法也解释得比较清楚。——译者注)
Dojo长久以来一直通过dojo.fromJson()和dojo.toJson对JSON操作提供良好的支持,但随着ECMAScript 5的JSON对象的出现及其API在浏览器中的普及,现在对JSON的解析和生成操作都有了标准化的API。Dojo1.7新加入的一个模块遵循了这个标准,它使Dojo在浏览器原生JSON对象存在的时候直接交给浏览器来生成或解析JSON。使用这个原生JSON对象的速度更快,同时,dojo/json模块采用了集成到打包系统中的功能检测系统(has() API),因此可以通过打包系统创建出针对某些浏览器的特殊包(例如移动设备包),这些包中的json模块将只有几字节。
使用dojo/json
要引入dojo/json模块,只需将其包含在依赖项列表中即可,就像加载其他模块一样:define(["dojo/json"],function(JSON){ //变量JSON可用于JSON数据的解析或串行化 });要解析一个JSON字符串,我们只需直接调用parse()方法:
define(["dojo/json"],function(JSON){ var someJsonString = getData(); // 解析JSON字符串 var myData = JSON.parse(someJsonString); });dojo/json的parse()方法与dojo.fromJson()有一些细微的差别。这两个都能正确解析任何有效的JSON,然而,parse方法最终会委托给原生的JSON解析器,这意味着你必须传给它格式上真正严格有效的JSON字符串才能保证正确的结果,而另一方面,dojo.fromJson()一直使用eval()方法来解析,因此它能接受任意有效的JavaScript表达式。为了保证向后兼容,dojo.fromJson()将仍然接受任意有效的JavaScript表达式,但dojo/json的parse()方法只能接受严格有效的JSON。
保证安全严格的解析
如果原生JSON解析器不可用,dojo/json默认会采用eval()方法来解析JSON。一般而言这个方法还是比较快的,但如果你需要解析来自非可信源的JSON,就应当使用严格模式(strict mode)。可以将parse()方法的第二个参数设置为true来启用严格模式。例如:var someJsonString = getData(); // 解析JSON字符串 var myData = JSON.parse(someJsonString,true);当原生JSON解析不可用时,严格模式解析会显得稍慢一些(这是因为需要做额外的检查)。而当原生JSON解析可用时,这第二个参数将被忽略,因为解析永远是严格的(而且一样快)。如下图所示,当原生解析不可用时,严格模式比非严格模式要慢2-3倍。原生解析的速度优势非常明显,因此dojo/json总是会优先考虑使用原生解析,而不管是否设置了严格模式参数。dojo/fromJson()函数从不使用原生解析,因此要比使用了原生解析的dojo/json慢3-4倍。
通常在服务器端采用安全措施要比在客户端更好,因此如果你从你自己的服务器获取数据,最好在服务器端使用一个安全有效的JSON串行化工具,而不是依赖于客户端的安全检查。parse()函数的严格模式应该只被用于来自非可信源的数据。
JSON串行化
dojo/json模块也可以用于串行化JSON。同样,这也是基于原生的JSON API,只要原生的JSON串行化函数可用就会交给它完成。串行化很简单,只需要传递一个JavaScript对象、数组、或者原始值给dojo/json模块的stringify函数:define(["dojo/json"],function(JSON){ var object = {foo:"bar"}; // 串行化为JSON字符串 var serialized = JSON.stringify(object); // 将返回'{"foo":"bar"}' });stringify方法还能接受一个replacer函数,可以用于对自定义数据类型的串行化。例如我们可以通过这个函数把日期数据串行化为UTC毫秒格式。另外,我们也可以用空格使串行化的数据具有易于阅读的缩进。要启用这个易读模式,只需将空格作为第三个参数:
var object = {nested:{props:true}}; // 串行化为JSON字符串 var serialized = JSON.stringify(object,null," "); // 返回具有缩进格式的串行化对象stringify()函数非常类似于以前的dojo.toJson()函数,但还是有一些不同:
- dojo.fromJson()函数会在它遇到的每个对象中寻找json()或__json__()方法作为自定义的串行化方法,但stringify()则会找toJson()方法。
- dojo.fromJson()函数不接受replacer函数作为参数,其第二个参数只是一个布尔值,表示是否以美观的形式(缩进)输出结果。如果使用美观形式(传true),就会使用dojo.toJsonIndentStr作为缩进字符串。
在无Base的Dojo中使用dojo/json
Dojo1.7和1.8设计成可以不需要完整的Dojo Base库就能打包应用。当Dojo Base在gzip后的大小小于40KB时,一些应用(尤其是移动设备上的应用)可能希望能做到代码最小化。dojo/json模块是Dojo中不再需要Dojo Base的众多模块之一。这个模块只需要一个模块加载器就能运行,没有任何其他依赖项。这使得超轻量级的应用成为可能。可参考 这篇博客文章进一步了解如何打造你自己的Dojo包。小结
Dojo1.7和1.8中处理JSON的方法:- 解析来自于可信源的JSON —— 使用dojo/json的parse(str)方法
- 解析来自于非可信源的JSON —— 使用dojo/json的parse(str,true)方法
- 解析来自可信源的JavaScript表达式(包含JSON)—— 使用dojo.fromJson(str)
- 将对象或原始值串行化为JSON —— 使用dojo/json的stringify(value)方法。
- 以美观的缩进形式串行化对象或原始值 —— 使用dojo/json的stringify(value," ")