JSON3入门

JSON3是时下流行的兼容了包括IE6、Opera7、Safari2和Netscape6等多个Javascript平台的JSON实现方案,目前的版本号是3.3.2。JSON是建立在松散的JavaScript语法集合之上、与编程语言无关的数据交换格式。该格式最初由Douglas Crockford提出,在第五版的 ECMAScript规范被标准化。2011年被批准的5.1版本修订了若干个关于日期序列化的语法。

JSON3暴露出两个功能:stringify()将JavaScript对象序列化成JSON,parse()从JSON字符串中转换成 JavaScript 对象。这是对 JSON2 的一个嵌入式替换。除了不符合下面提到的日期序列化,这两个函数完全遵照ECMAScript的规范。

JSON3解析不使用eval和正则表达式,为在边界明确的过时的或者移动环境下提供了良好的安全性和性能。jsPref上提供了完整的基线测试集

对比JSON2

JSON3:

  • 正确的序列化原始包装对象;
  • 当序列化循环结构时会抛出TypeError(JSON2直到调用堆栈溢出);
  • 利用特征测试去检测损坏的或不完整的原生JSON实现(JSON2只检查的本地函数的存在。 测试只在运行时执行一次,所以分析或序列化值时,没有额外的性能开销。

JSON3 v3.2.3完全兼容Prototype 1.6.1和之前的版本。
与JSON2对比,JSON3没有:

  • 为Boolean、Number和String添加toJSON()方法。关于这部分没有任何标准,并且让stringify()实现的设计显得多余。
  • 为Date.prototype添加toJSON()toISOString()方法。具体参加下面日期序列化部分。

日期序列化

JSON3没有定义Date#toISOString()或者Date#toJSON(),使其脱离了规范定义。这使其兼容了CommonJS,同时避免污染native原型。相应地,日期序列化在其内部由stringify()高效地实现了。如果一个日期对象没有自定义toJSON()方法,它将被序列化为一个简单的ISO 8601日期时间字符串

几个本地的Date#toJSON实现生成的日期时间字符串在规范上并不符合语法。比如,所有的Safari 4 以及 JSON2,不能正确序列扩展的年。另外,JSON2和旧的实现省略了日期时间字符串中的毫秒。(在ES 5中是可选择的,在5.1中是必须要求的。) 最后在 Safari 4和5的所有版本中,序列化一个无效的日期会产生一个”Invalid Date”,而不是null ;这些环境展现了其他序列化错误,但是JSON3将覆盖本地stringify()实现。

部分日期序列化代码改自date-shim工程

使用示例

页面代码

1
2
3
4
5
6
7
8
9
10
11
12
<script src="//cdnjs.cloudflare.com/ajax/libs/json3/3.3.2/json3.min.js"></script>
<script>
JSON.stringify({"Hello": 123});
// => '{"Hello":123}'
JSON.parse("[[1, 2, 3], 1, 2, 3, 4]", function (key, value) {
if (typeof value == "number") {
value = value % 2 ? "Odd" : "Even";
}
return value;
});
// => [["Odd", "Even", "Odd"], "Odd", "Even", "Odd", "Even"]
</script>

当在web浏览器中使用时,JSON3暴露了一个额外的包含noConfict()renlnContext()函数的JSON3对象,以及别名为stringify()parse()函数。

noConfict()和renlnContext()函数

  • JSON3.noConflict() 还原全局JSON对象的原始值,返回一个引用JSON3对象;
  • JSON3.runInContext([context, exports])使用给定上下文对象初始化JSON3,(比如window、 global等),或在忽略下的全局对象。如果指定了暴露对象,stringify()、parse()和 runInContext() 函数将会附着它来代替一个新的对象。

异步模块加载

为了兼容RequiredJS、curl.js以及其他异步模块加载机制,JSON3定义了一个异步模块。

1
2
3
4
5
6
7
8
9
10
11
<script src="//cdnjs.cloudflare.com/ajax/libs/require.js/2.1.10/require.js"></script>
<script>
require({
"paths": {
"json3": "./path/to/json3"
}
}, ["json3"], function (JSON) {
JSON.parse("[1, 2, 3]");
// => [1, 2, 3]
});
</script>

为避免与第三方脚本的问题,即使在模块加载器中使用,JSON3 也暴露到全局范围。如果这种行为不是期望的,JSON3.noConflict()可用于全局JSON对象恢复其原始值。
注:如果您打算在其他模块边使用JSON3,请不要简单地将这些模块组合串连在一起,因为这将导致一个脚本重复定义调用从而引起AMD装载机的错误。如果需要在生产环境使用压缩的js文件,可以使用r.js。

CommonJS环境

1
2
3
var JSON3 = require("./path/to/json3");
JSON3.parse("[1, 2, 3]");
// => [1, 2, 3]

JavaScript引擎

1
2
3
load("path/to/json3.js");
JSON.stringify({"Hello": 123, "Good-bye": 456}, ["Hello"], "\t");
// => '{\n\t"Hello": 123\n}'

stringify使用示例

JSON.stringify(value [, replacer] [, space])

  • value:是必须要的字段。就是你输入的对象,比如数组啊,类啊等等。
  • replacer:可选,分为2种方式:一种是方法,第二种是数组。
  • space:可选,定义缩进几个字符。
1
2
3
4
5
6
7
var preview = JSON.stringify(value, function(key, value){
if(key == "Start_Time" || key == "End_Time"){
var dt = Date.parse(value);
value = dt/1000;
}
return value;
}, 2);

兼容性

JSON3已经被以下网页浏览器、CommonJS环境以及JavaScript引擎测试。

网页浏览器

  • Windows IE 6.0或更高
  • Mozilla Firefox 1.0或更高
  • Apple Safari 2.0或更高
  • Opera 7.02或更高
  • Mozilla 1.0、Netscape 6.2.3和SeaMonkey 1.0 或更高

CommonJS环境

  • Node 0.2.6或更高
  • RingoJS 0.4或更高
  • Narwhal 0.3.2或更高

JavaScript引擎

  • ozilla Rhino 1.5R5或更高
  • WebKit JSC
  • Google V8

已知的不兼容

试图序列化参数对象可能在跨环境下由于不同的规范版本产生不一致的结果。作为一种变通方法,请先转换参数对象到一个数组:JSON.stringify([].slice.call(arguments, 0))

所需本地方法

JSON3假设存在和ECMAScript规范中的功能描述一致的如下方法:

  • The Number, String, Array, Object, Date, SyntaxError, and TypeError constructors.
  • String.fromCharCode
  • Object#toString
  • Function#call
  • Math.floor
  • Number#toString
  • Date#valueOf
  • String.prototype: indexOf, charCodeAt, charAt, slice
  • Array.prototype: push, pop, join

JSON3代码库

1
2
$ git clone git://github.com/bestiejs/json3.git
$ cd json3

JSON3遵循MTI License。

参考文献

[1] JSON3
[2] JSON.stringify 语法讲解