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

谢谢

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

我想将对象字符串化为:

{"a":"foo"}

当前回答

在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}])


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

其他回答

您可以尝试JSON解析器库:treedoc。它支持循环引用,并使用引用消除重复对象。

纱线添加树文档

import {TD} from 'treedoc'
TD.stringify(obj);

如果您需要更多定制

import {TD, TDEncodeOption} from 'treedoc'

const opt = new TDEncodeOption();
opt.coderOption.setShowType(true).setShowFunction(true);
opt.jsonOption.setIndentFactor(2);
return TD.stringify(obj, opt);

查看器可以查看生成的JSON文件http://treedoc.org,支持通过JSON节点引用进行导航。

我是这个图书馆的作者

这里有一个解决方案:

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

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]'}}"

我们使用对象扫描进行数据处理,这可能是一个可行的解决方案。这就是它的工作方式(也可以正确修剪数组)

.作为控制台包装{最大高度:100%!重要;顶部:0}<script type=“module”>导入对象扫描自'https://cdn.jsdelivr.net/npm/object-scan@18.1.2/lib/index.min.js';const prune=(data)=>对象扫描(['**']{rtn:'计数',filterFn:({isCircular,父级,属性})=>{if(isCircular){if(Array.isArray(父级)){parent.splice(属性,1);}其他{删除父项[属性];}返回true;}return false;},breakFn:({isCircular})=>isCircular==true})(数据);常量obj={a:'foo',c:[0]};obj.b=对象;obj.c.push(obj);console.log(obj);//=><ref*1>{a:'foo',c:[0,[Circular*1]],b:[Circulal*1]}console.log(prune(obj));//返回循环计数// => 2console.log(obj);//=>{a:'foo',c:[0]}</script>

免责声明:我是物体扫描的作者

在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}])


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

使用带有自定义替换符的JSON.stringify。例如:

// Demo: Circular reference
var circ = {};
circ.circ = circ;

// Note: cache should not be re-used by repeated calls to JSON.stringify.
var cache = [];
JSON.stringify(circ, (key, value) => {
  if (typeof value === 'object' && value !== null) {
    // Duplicate reference found, discard key
    if (cache.includes(value)) return;

    // Store value in our collection
    cache.push(value);
  }
  return value;
});
cache = null; // Enable garbage collection

本例中的替换符并非100%正确(取决于您对“重复”的定义)。在以下情况下,将丢弃一个值:

var a = {b:1}
var o = {};
o.one = a;
o.two = a;
// one and two point to the same object, but two is discarded:
JSON.stringify(o, ...);

但概念是:使用自定义替换器,并跟踪解析的对象值。

作为es6中编写的实用函数:

// safely handles circular references
JSON.safeStringify = (obj, indent = 2) => {
  let cache = [];
  const retVal = JSON.stringify(
    obj,
    (key, value) =>
      typeof value === "object" && value !== null
        ? cache.includes(value)
          ? undefined // Duplicate reference found, discard key
          : cache.push(value) && value // Store value in our collection
        : value,
    indent
  );
  cache = null;
  return retVal;
};

// Example:
console.log('options', JSON.safeStringify(options))