我有一个大对象要转换成JSON并发送。然而,它具有圆形结构。我想丢弃任何存在的循环引用,并发送任何可以字符串化的引用。我该怎么做?
谢谢
var obj = {
a: "foo",
b: obj
}
我想将对象字符串化为:
{"a":"foo"}
我有一个大对象要转换成JSON并发送。然而,它具有圆形结构。我想丢弃任何存在的循环引用,并发送任何可以字符串化的引用。我该怎么做?
谢谢
var obj = {
a: "foo",
b: obj
}
我想将对象字符串化为:
{"a":"foo"}
当前回答
这里有一个解决方案:
仅删除循环(而不是所有重复的对象引用,到目前为止这里发布的大多数解决方案也是如此),不是不必要的冗长,速度快,不需要任何库依赖关系。
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]'}}"
其他回答
注意,还有一个由Douglas Crockford实现的JSON.decycle方法。看看他的cycle.js。这允许您对几乎任何标准结构进行字符串化:
var a = [];
a[0] = a;
a[1] = 123;
console.log(JSON.stringify(JSON.decycle(a)));
// result: '[{"$ref":"$"},123]'.
您也可以使用逆循环方法重新创建原始对象。因此,您不必从对象中删除循环来将其字符串化。
然而,这对于DOM节点(在现实生活中,这是周期的典型原因)不起作用。例如,这将抛出:
var a = [document.body];
console.log(JSON.stringify(JSON.decycle(a)));
我做了一个叉来解决这个问题(参见我的cycle.js叉)。这应该很好:
var a = [document.body];
console.log(JSON.stringify(JSON.decycle(a, true)));
注意,在我的fork中,JSON.decycle(变量)的工作方式与原始一样,当变量包含DOM节点/元素时,将抛出异常。
当您使用JSON.decycle(variable,true)时,您接受这样一个事实,即结果是不可逆的(retrocycle不会重新创建DOM节点)。但DOM元素在某种程度上应该是可识别的。例如,如果一个div元素有一个id,那么它将被替换为字符串“div#id of the element”。
我这样解决这个问题:
var util = require('util');
// Our circular object
var obj = {foo: {bar: null}, a:{a:{a:{a:{a:{a:{a:{hi: 'Yo!'}}}}}}}};
obj.foo.bar = obj;
// Generate almost valid JS object definition code (typeof string)
var str = util.inspect(b, {depth: null});
// Fix code to the valid state (in this example it is not required, but my object was huge and complex, and I needed this for my case)
str = str
.replace(/<Buffer[ \w\.]+>/ig, '"buffer"')
.replace(/\[Function]/ig, 'function(){}')
.replace(/\[Circular]/ig, '"Circular"')
.replace(/\{ \[Function: ([\w]+)]/ig, '{ $1: function $1 () {},')
.replace(/\[Function: ([\w]+)]/ig, 'function $1(){}')
.replace(/(\w+): ([\w :]+GMT\+[\w \(\)]+),/ig, '$1: new Date("$2"),')
.replace(/(\S+): ,/ig, '$1: null,');
// Create function to eval stringifyed code
var foo = new Function('return ' + str + ';');
// And have fun
console.log(JSON.stringify(foo(), null, 4));
这里有一个解决方案:
仅删除循环(而不是所有重复的对象引用,到目前为止这里发布的大多数解决方案也是如此),不是不必要的冗长,速度快,不需要任何库依赖关系。
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]'}}"
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}
我为LoggingUtilities类创建了以下方法。以下方法获取源和目标对象,并通过给定的maxLevel将源分配给目标。
static assignObjectByLevel(
sourceObject: any,
targetObject: any,
currentLevel: number = 0,
maxLevel: number = 3,
showUndefinedValues = false
): any {
if (currentLevel >= maxLevel) {
return;
}
const objQueue = [];
for (const key in sourceObject) {
if (sourceObject.hasOwnProperty(key)) {
const value = sourceObject[key];
if (typeof value === "object") {
objQueue.push({ key, value });
} else {
targetObject[key] = value;
}
} else {
if (showUndefinedValues) {
targetObject[key] = "undefined/null";
}
}
}
while (objQueue.length > 0) {
const objVal = objQueue.pop();
currentLevel++;
targetObject[objVal.key] = {};
this.assignObjectByLevel(
objVal.value,
targetObject[objVal.key],
currentLevel,
maxLevel,
false
);
}
}
用法示例:
const logObjParam = {
level1: "value1",
level2: {
value2: "value2",
level3: {
value3: "value3",
level4: {
value4: " value4",
level5: {
value5: " value5",
},
},
},
},
};
let logObj = {};
this.assignObjectByLevel(logObjParam, logObj);
结果:
{
"level1": "value1",
"level2": {
"value2": "value2",
"level3": {
"value3": "value3",
"level4": {}
}
}
}