我有一个大对象要转换成JSON并发送。然而,它具有圆形结构。我想丢弃任何存在的循环引用,并发送任何可以字符串化的引用。我该怎么做?

谢谢

var obj = {
  a: "foo",
  b: obj
}

我想将对象字符串化为:

{"a":"foo"}

当前回答

If

console.log(JSON.stringify(object));

结果是

TypeError:循环对象值

然后,您可能想要这样打印:

var output = '';
for (property in object) {
  output += property + ': ' + object[property]+'; ';
}
console.log(output);

其他回答

var a={b:"b"};
a.a=a;
JSON.stringify(preventCircularJson(a));

评估结果为:

"{"b":"b","a":"CIRCULAR_REFERENCE_REMOVED"}"

具有以下功能:

/**
 * Traverses a javascript object, and deletes all circular values
 * @param source object to remove circular references from
 * @param censoredMessage optional: what to put instead of censored values
 * @param censorTheseItems should be kept null, used in recursion
 * @returns {undefined}
 */
function preventCircularJson(source, censoredMessage, censorTheseItems) {
    //init recursive value if this is the first call
    censorTheseItems = censorTheseItems || [source];
    //default if none is specified
    censoredMessage = censoredMessage || "CIRCULAR_REFERENCE_REMOVED";
    //values that have allready apeared will be placed here:
    var recursiveItems = {};
    //initaite a censored clone to return back
    var ret = {};
    //traverse the object:
    for (var key in source) {
        var value = source[key]
        if (typeof value == "object") {
            //re-examine all complex children again later:
            recursiveItems[key] = value;
        } else {
            //simple values copied as is
            ret[key] = value;
        }
    }
    //create list of values to censor:
    var censorChildItems = [];
    for (var key in recursiveItems) {
        var value = source[key];
        //all complex child objects should not apear again in children:
        censorChildItems.push(value);
    }
    //censor all circular values
    for (var key in recursiveItems) {
        var value = source[key];
        var censored = false;
        censorTheseItems.forEach(function (item) {
            if (item === value) {
                censored = true;
            }
        });
        if (censored) {
            //change circular values to this
            value = censoredMessage;
        } else {
            //recursion:
            value = preventCircularJson(value, censoredMessage, censorChildItems.concat(censorTheseItems));
        }
        ret[key] = value

    }

    return ret;
}

我建议从@isaacs中检查json字符串安全性——它在NPM中使用。

顺便说一下,如果你没有使用Node.js,你可以从源代码的相关部分复制并粘贴第4-27行。

要安装:

$ npm install json-stringify-safe --save

要使用:

// Require the thing
var stringify = require('json-stringify-safe');

// Take some nasty circular object
var theBigNasty = {
  a: "foo",
  b: theBigNasty
};

// Then clean it up a little bit
var sanitized = JSON.parse(stringify(theBigNasty));

这产生了:

{
  a: 'foo',
  b: '[Circular]'
}

注意,就像@Rob W提到的普通JSON.stringify函数一样,您也可以通过将“replacer”函数作为第二个参数传递给stringify()来自定义净化行为。如果您发现自己需要一个简单的示例来说明如何做到这一点,我只是在这里编写了一个自定义替换器,它将错误、正则表达式和函数强制转换为人类可读的字符串。

这里有一个解决方案:

仅删除循环(而不是所有重复的对象引用,到目前为止这里发布的大多数解决方案也是如此),不是不必要的冗长,速度快,不需要任何库依赖关系。

function replaceCycles(obj, replacement = undefined, seen = new WeakSet()) {
  if (typeof obj === 'object')
    if (seen.has(obj))
      return replacement 
    else {
      seen.add(obj)
      const newObj = {}
      for (const key in obj)
        newObj[key] = replaceCycles(obj[key], replacement, seen)
      seen.delete(obj)
      return newObj
    }
  else
    return obj
}

用法:

const a = {
  b: 'v1',
  c: {
    d: 'v2'
  }
}

a.e = a.c
a.c.f = a.c

console.log(JSON.stringify(replaceCycles(a, '[CYCLE]')))

输出:

"{'b':'v1','c':{'d':'v2','f':'[CYCLE]'},'e':{'d':'v2','f':'[CYCLE]'}}"

在Node.js中,您可以使用util.inspect(object)。它会自动将循环链接替换为“[circular]”。


尽管是内置的(不需要安装),但必须导入它

import * as util from 'util' // has no default export
import { inspect } from 'util' // or directly
// or 
var util = require('util')

要使用它,只需调用

console.log(util.inspect(myObject))

还要注意,您可以传递options对象以进行检查(请参见上面的链接)

inspect(myObject[, options: {showHidden, depth, colors, showProxy, ...moreOptions}])


请阅读下面的评论并给予表扬。。。

我知道这是一个老问题,但我想建议一个我创建的NPM包,叫做智能循环,它的工作方式与其他建议的方式不同。如果您使用的是大而深的对象,它特别有用。

一些功能包括:

将循环引用或对象内部简单重复的结构替换为导致其首次出现的路径(而不仅仅是字符串〔circular〕);通过在广度优先搜索中查找循环,该包确保了该路径尽可能小,这在处理非常大和深度的对象时非常重要,因为这些对象的路径可能非常长且难以遵循(JSON.stringify中的自定义替换是DFS);允许个性化替换,方便简化或忽略对象的不重要部分;最后,路径完全以访问引用字段所需的方式编写,这可以帮助您进行调试。