序列化包含循环对象值的对象

2022-08-30 01:54:33

我有一个对象(解析树),其中包含对其他节点的引用子节点。

我想使用 序列化此对象,但我得到JSON.stringify()

类型错误:循环对象值

因为我提到的结构。

我该如何解决这个问题?对我来说,这些对其他节点的引用是否在序列化对象中表示并不重要。

另一方面,在创建这些属性时从对象中删除这些属性似乎很乏味,我不想对解析器(narcissus)进行更改。


答案 1

使用 的第二个参数 ,即 replacer 函数,排除已序列化的对象: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;
});

http://jsfiddle.net/mH6cJ/38/

正如在其他注释中正确指出的那样,此代码删除了每个“已见过”的对象,而不仅仅是“递归”对象。

例如,对于:

a = {x:1};
obj = [a, a];

结果将不正确。如果你的结构是这样的,你可能想使用Crockford的decycle或这个(更简单的)函数,它只是用nulls替换递归引用:

function decycle(obj, stack = []) {
    if (!obj || typeof obj !== 'object')
        return obj;
    
    if (stack.includes(obj))
        return null;

    let s = stack.concat([obj]);

    return Array.isArray(obj)
        ? obj.map(x => decycle(x, s))
        : Object.fromEntries(
            Object.entries(obj)
                .map(([k, v]) => [k, decycle(v, s)]));
}

//

let a = {b: [1, 2, 3]}
a.b.push(a);

console.log(JSON.stringify(decycle(a)))

答案 2

这是一种替代答案,但是由于很多人来这里是为了调试他们的循环对象,并且没有一个很好的方法来做到这一点,而无需拉入一堆代码,所以这里去了。

一个不如 console.table() 那么出名的功能。只需调用 ,它就会以表格格式在控制台中记录变量,这使得仔细阅读变量的内容变得相当容易和方便。JSON.stringify()console.table(whatever);