我有一个对象(解析树),它包含对其他节点的引用的子节点。
我想使用JSON.stringify()
序列化此对象,但由于我提到的构造,我得到:TypeError: cyclic object value
。
我怎么能解决这个问题?在序列化对象中是否表示了对其他节点的这些引用并不重要。
另一方面,在创建对象时从对象中删除这些属性似乎很乏味,我不想对解析器(narcissus)进行更改。
答案 0 :(得分:195)
使用stringify
的第二个参数replacer function来排除已经序列化的对象:
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;
});
正如其他评论中正确指出的那样,此代码删除了每个“看到”的对象,而不仅仅是“递归”对象。
例如,对于:
a = {x:1};
obj = [a, a];
结果不正确。如果你的结构是这样的,那么Crockford的decycle是一个更好的选择。
答案 1 :(得分:3)
这是一种替代答案,但是由于很多人来这里调试它们的圆形对象,而且如果没有大量代码的话,这实际上不是一种很棒的方法。 / p>
console.table()
是尚不知名的JSON.stringify()
功能。只需调用console.table(whatever);
,它就会以表格格式将变量记录在控制台中,从而使读取变量的内容变得相当容易和方便。
答案 2 :(得分:2)
我创建了一个GitHub Gist,它能够检测循环结构并对它们进行去除和编码:https://gist.github.com/Hoff97/9842228
转换只需使用JSONE.stringify / JSONE.parse。 它还解码和编码功能。如果要禁用此功能,只需删除第32-48行和第61-85行。
var strg = JSONE.stringify(cyclicObject);
var cycObject = JSONE.parse(strg);
你可以在这里找到一个例子:
答案 3 :(得分:1)
更安全,它显示循环对象的位置。
<script>
var jsonify=function(o){
var seen=[];
var jso=JSON.stringify(o, function(k,v){
if (typeof v =='object') {
if ( !seen.indexOf(v) ) { return '__cycle__'; }
seen.push(v);
} return v;
});
return jso;
};
var obj={
g:{
d:[2,5],
j:2
},
e:10
};
obj.someloopshere = [
obj.g,
obj,
{ a: [ obj.e, obj ] }
];
console.log('jsonify=',jsonify(obj));
</script>
产生
jsonify = {"g":{"d":[2,5],"j":2},"e":10,"someloopshere":[{"d":[2,5],"j":2},"__cycle__",{"a":[10,"__cycle__"]}]}
答案 4 :(得分:1)
function stringifyObject ( obj ) {
if ( _.isArray( obj ) || !_.isObject( obj ) ) {
return obj.toString()
}
var seen = [];
return JSON.stringify(
obj,
function( key, val ) {
if (val != null && typeof val == "object") {
if ( seen.indexOf( val ) >= 0 )
return
seen.push( val )
}
return val
}
);
}
缺少前提条件,否则数组对象中的整数值被截断,即[[08.11.2014 12:30:13,1095]] 1095减少到095。
答案 5 :(得分:0)
我创建了一个github项目,它可以序列化循环对象并恢复该类,如果你将它保存在serializename属性中,如String
var d={}
var a = {b:25,c:6,enfant:d};
d.papa=a;
var b = serializeObjet(a);
assert.equal( b, "{0:{b:25,c:6,enfant:'tab[1]'},1:{papa:'tab[0]'}}" );
var retCaseDep = parseChaine(b)
assert.equal( retCaseDep.b, 25 );
assert.equal( retCaseDep.enfant.papa, retCaseDep );
https://github.com/bormat/serializeStringifyParseCyclicObject
编辑: 我已将我的脚本转换为NPM https://github.com/bormat/borto_circular_serialize,并且我将函数名称从法语更改为英语。
答案 6 :(得分:0)
假设您要做要保留循环引用(即用非循环编码来编码循环数据结构),这当然比仅删除或忽略它们要耗费更多精力:>
道格拉斯·克罗克福德的答案:cylce.js
我对该方法的(性能)改进:my answer to related SO question
答案 7 :(得分:0)
nodejs 模块 serialijse
提供了一种很好的方法来处理包含循环或 javascript 类实例的任何类型的 JSON 对象。
const { serialize, deserialize } = require("serialijse");
var Mary = { name: "Mary", friends: [] };
var Bob = { name: "Bob", friends: [] };
Mary.friends.push(Bob);
Bob.friends.push(Mary);
var group = [ Mary, Bob];
console.log(group);
// testing serialization using JSON.stringify/JSON.parse
try {
var jstr = JSON.stringify(group);
var jo = JSON.parse(jstr);
console.log(jo);
} catch (err) {
console.log(" JSON has failed to manage object with cyclic deps");
console.log(" and has generated the following error message", err.message);
}
// now testing serialization using serialijse serialize/deserialize
var str = serialize(group);
var so = deserialize(str);
console.log(" However Serialijse knows to manage object with cyclic deps !");
console.log(so);
assert(so[0].friends[0] == so[1]); // Mary's friend is Bob
这个序列化器支持