我有一个大对象要转换成JSON并发送。然而,它具有圆形结构。我想丢弃任何存在的循环引用,并发送任何可以字符串化的引用。我该怎么做?
谢谢
var obj = {
a: "foo",
b: obj
}
我想将对象字符串化为:
{"a":"foo"}
我有一个大对象要转换成JSON并发送。然而,它具有圆形结构。我想丢弃任何存在的循环引用,并发送任何可以字符串化的引用。我该怎么做?
谢谢
var obj = {
a: "foo",
b: obj
}
我想将对象字符串化为:
{"a":"foo"}
当前回答
循环引用时,此代码将失败:
JSON.stringify(circularReference);
// TypeError: cyclic object value
使用以下代码:
const getCircularReplacer = () => {
const seen = new WeakSet();
return (key, value) => {
if (typeof value === "object" && value !== null) {
if (seen.has(value)) {
return;
}
seen.add(value);
}
return value;
};
};
JSON.stringify(circularReference, getCircularReplacer());
其他回答
使用带有自定义替换符的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))
function myStringify(obj, maxDeepLevel = 2) {
if (obj === null) {
return 'null';
}
if (obj === undefined) {
return 'undefined';
}
if (maxDeepLevel < 0 || typeof obj !== 'object') {
return obj.toString();
}
return Object
.entries(obj)
.map(x => x[0] + ': ' + myStringify(x[1], maxDeepLevel - 1))
.join('\r\n');
}
本线程中的大多数答案都是专门针对JSON.stringify使用的——它们没有显示如何实际删除原始对象树中的循环引用。(好吧,除了之后再次调用JSON.parse之外——这需要重新分配,并且会产生更高的性能影响)
要从源对象树中删除循环引用,可以使用以下函数:https://stackoverflow.com/a/63952549/2441655
然后,可以使用这些通用的循环引用移除器函数安全地调用循环引用敏感函数(如JSON.stringify):
const objTree = {normalProp: true};
objTree.selfReference = objTree;
RemoveCircularLinks(objTree); // without this line, the JSON.stringify call errors
console.log(JSON.stringify(objTree));
superserial完全序列化JavaScript对象。
https://github.com/denostack/superserial
用法:
const serializer = new Serializer();
const nodes = [{ self: null as any, siblings: [] as any[] }, {
self: null as any,
siblings: [] as any[],
}];
nodes[0].self = nodes[0];
nodes[0].siblings = nodes;
nodes[1].self = nodes[1];
nodes[1].siblings = nodes;
const serialized = serializer.serialize(nodes);
console.log(serialized);
输出:
[$1,$2];{"self":$1,"siblings":$0};{"self":$2,"siblings":$0}
您可以尝试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节点引用进行导航。
我是这个图书馆的作者