这是带有循环引用的数据结构的示例:
function makeToolshed(){
var nut = {name: 'nut'}, bolt = {name: 'bolt'};
nut.needs = bolt; bolt.needs = nut;
return { nut: nut, bolt: bolt };
}
当你想KEEP循环引用(当你反序列化恢复它们,而不是“的摧毁”),你有2个选择,我会在这里进行比较。首先是Douglas Crockford的cycle.js,其次是我的西伯利亚软件包。两者都通过首先“回收”对象来工作,即构造“包含相同信息”的另一个对象(没有任何循环引用)。
克罗克福德先生先行:
JSON.decycle(makeToolshed())
如您所见,JSON的嵌套结构得以保留,但是有一个新东西,即具有特殊$ref
属性的对象。让我们看看它是如何工作的。
root = makeToolshed();
[root.bolt === root.nut.needs, root.nut.needs.needs === root.nut]; // retutrns [true,true]
美元符号代表根。.bolt
其$ref
告诉我们,.bolt
是“已经看到”对象,特殊属性的值(在这里,字符串$ [“螺母”] [“需求”])告诉我们哪里,最先看到的===
上面。第二$ref
和第二===
以上。
让我们使用一个合适的深度平等测试(即,deepGraphEqual
从对这个问题的公认答案中的Anders Kaseorg 函数)来看克隆是否有效。
root = makeToolshed();
clone = JSON.retrocycle(JSON.decycle(root));
deepGraphEqual(root, clone) // true
serialized = JSON.stringify(JSON.decycle(root));
clone2 = JSON.retrocycle(JSON.parse(serialized));
deepGraphEqual(root, clone2); // true
现在,西伯利亚:
JSON.Siberia.forestify(makeToolshed())
西伯利亚不尝试模仿“经典” JSON,没有嵌套结构。对象图以“平面”方式描述。对象图的每个节点都变成一棵扁平树(带有纯整数值的纯键值对列表),它是.forest.
索引0处的根对象,索引较高的处则找到的其他节点。对象图和负值(林中某棵树的某些键的负值)指向该atoms
数组(该数组是通过types数组键入的,但此处将跳过键入细节)。所有终端节点都在atoms表中,所有非终端节点都在forest表中,您可以立即看到对象图有多少个节点,即forest.length
。让我们测试一下是否可行:
root = makeToolshed();
clone = JSON.Siberia.unforestify(JSON.Siberia.forestify(root));
deepGraphEqual(root, clone); // true
serialized = JSON.Siberia.stringify(JSON.Siberia.forestify(root));
clone2 = JSON.Siberia.unforestify(JSON.Siberia.unstringify(serialized));
deepGraphEqual(root, clone2); // true
比较
稍后会添加部分。