Loi*_*ros 143 javascript json jsonserializer stringify
我有一个对象(解析树),其中包含对其他节点的引用的子节点.
我想序列化这个对象,使用JSON.stringify()
,但我得到:JSON.stringify()
因为我提到的结构.
我怎么能解决这个问题?对于我来说,序列化对象中是否表示了对其他节点的这些引用并不重要.
另一方面,在创建对象时从对象中删除这些属性似乎很乏味,我不想对解析器(narcissus)进行更改.
geo*_*org 205
使用的第二个参数stringify
,该替代品的功能,以排除已序列化对象:
var seen = [];
JSON.stringify(obj, function(key, val) {
if (val != null && typeof val == "object") {
if (seen.indexOf(val) >= 0) {
return;
}
seen.push(val);
}
return val;
});
Run Code Online (Sandbox Code Playgroud)
正如在其他注释中正确指出的那样,此代码删除了每个"看到"的对象,而不仅仅是"递归"对象.
例如,对于:
a = {x:1};
obj = [a, a];
Run Code Online (Sandbox Code Playgroud)
结果将是不正确的.如果您的结构是这样的,Crockford的decycle是一个更好的选择.
以下是具有循环引用的数据结构的示例:
function makeToolshed(){
var nut = {name: 'nut'}, bolt = {name: 'bolt'};
nut.needs = bolt; bolt.needs = nut;
return { nut: nut, bolt: bolt };
}
Run Code Online (Sandbox Code Playgroud)
当您希望保留循环引用(在反序列化时恢复它们,而不是“破坏”它们)时,您有两种选择,我将在此处进行比较。第一个是 Douglas Crockford 的Cycle.js,第二个是我的siberia包。两者的工作原理都是首先“回收”对象,即构造另一个“包含相同信息”的对象(没有任何循环引用)。
克罗克福德先生首先说道:
JSON.decycle(makeToolshed())
Run Code Online (Sandbox Code Playgroud)
正如你所看到的,JSON 的嵌套结构被保留,但有一个新的东西,那就是具有特殊$ref
属性的对象。让我们看看它是如何工作的。
root = makeToolshed();
[root.bolt === root.nut.needs, root.nut.needs.needs === root.nut]; // retutrns [true,true]
Run Code Online (Sandbox Code Playgroud)
美元符号代表根。.bolt
having$ref
告诉我们这.bolt
是一个“已经看到”的对象,并且该特殊属性的值(这里是字符串 $["nut"]["needs"])告诉我们在哪里,请参见===
上面的第一个。对于第二个$ref
和上面的第二个也是如此===
。
让我们使用合适的深度相等测试(即 Anders Kaseorg 的deepGraphEqual
函数,来自此问题的接受答案)来查看克隆是否有效。
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
Run Code Online (Sandbox Code Playgroud)
现在,西伯利亚:
JSON.Siberia.forestify(makeToolshed())
Run Code Online (Sandbox Code Playgroud)
Siberia 并没有尝试模仿“经典”JSON,没有嵌套结构。对象图以“平面”方式描述。对象图的每个节点都变成一棵平面树(带有纯整数值的普通键值对列表),它是 中的一个条目 在.forest.
索引零处,我们找到根对象,在更高的索引处,我们找到 的其他节点对象图和负值(森林中某棵树的某些键的)指向数组atoms
(通过 types 数组输入,但我们将在这里跳过输入细节)。所有终端节点都在原子表中,所有非终端节点都在森林表中,您可以立即看到对象图有多少个节点,即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
Run Code Online (Sandbox Code Playgroud)
稍后将添加部分。
我目前正在重构该包。中心思想和算法保持不变,但新版本将更易于使用,顶层 API 将有所不同。我很快就会归档 siberia 并展示重构版本,我将其称为 objectgraph。请继续关注,本月(2020 年 8 月)将会发生
啊,还有超短版来对比。对于“指针”,我需要与整数占用一样多的空间,因为我的“指向已经看到的节点的指针”(事实上,指向所有节点,无论是否已经看到)只是整数。在 Crockford 先生的版本中,存储“指针”所需的数量仅受对象图大小的限制。这使得克罗克福德先生版本的最坏情况的复杂性变得极其可怕。Crockford 先生给了我们“另一种冒泡排序”。我不是在开玩笑。太糟糕了。如果你不相信,有测试,你可以从包的自述文件开始找到它们(也将在本月,2020 年 8 月,将它们转换为符合 benchmark.js 的标准)
这是一种替代答案,但是由于很多人来这里是为了调试他们的循环对象,并且没有真正的好方法可以在不引入一堆代码的情况下做到这一点,所以这里是。
一个功能,并不像众所周知的JSON.stringify()
是console.table()
。只需调用console.table(whatever);
,它就会以表格格式在控制台中记录变量,从而非常容易和方便地阅读变量的内容。
归档时间: |
|
查看次数: |
116507 次 |
最近记录: |