我有一个大对象要转换成JSON并发送。然而,它具有圆形结构。我想丢弃任何存在的循环引用,并发送任何可以字符串化的引用。我该怎么做?
谢谢
var obj = {
a: "foo",
b: obj
}
我想将对象字符串化为:
{"a":"foo"}
我有一个大对象要转换成JSON并发送。然而,它具有圆形结构。我想丢弃任何存在的循环引用,并发送任何可以字符串化的引用。我该怎么做?
谢谢
var obj = {
a: "foo",
b: obj
}
我想将对象字符串化为:
{"a":"foo"}
当前回答
我知道这个问题很老,有很多很好的答案,但我发布这个答案是因为它有新的味道(es5+)
Object.defineProperties(JSON{refStringify:{值:函数(obj){let objMap=new Map();let stringified=JSON.stringify(obj,函数(键、值){//仅适用于对象if(值类型==“对象”){//如果具有值,则返回对它的引用if(objMap.has(value))return objMap.get(value);objMap.set(值,`ref${objMap.size+1}`);}返回值;});返回字符串;}},参考解析:{value:函数(str){let parsed=JSON.parse(str);let objMap=_createObjectMap(已解析);objMap.forEach((value,key)=>_replaceKeyWithObject(value,key));返回解析;}},});//***************************示例设a={b: 32中,c:{获取a(){返回a;},获取c(){返回a.c;}}};let stringified=JSON.refStringify(a);let parsed=JSON.refParse(字符串化,2);console.log(已解析,JSON.refStringify(已解析));//***************************/示例//***************************助手函数_createObjectMap(obj){let objMap=new Map();JSON.stringify(obj,(key,value)=>{if(值类型==“对象”){if(objMap.has(value))return objMap.get(value);objMap.set(值,`ref${objMap.size+1}`);}返回值;});返回objMap;}函数_replaceKeyWithObject(key,obj,replaceWithObject=obj){Object.keys(obj).forEach(k=>{设val=obj[k];if(val==键)return(obj[k]=replaceWithObject);if(typeof val=='object'&&val!=replaceWithObject)_replaceKeyWithObject(key,val,replaceWithObject);});}
其他回答
我建议从@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()来自定义净化行为。如果您发现自己需要一个简单的示例来说明如何做到这一点,我只是在这里编写了一个自定义替换器,它将错误、正则表达式和函数强制转换为人类可读的字符串。
我在github上找到了循环json库,它很好地解决了我的问题。
我发现一些有用的好功能:
支持多平台使用,但到目前为止我只使用node.js测试了它。API是相同的,所以您需要做的就是将其包含并用作JSON替换。它有自己的解析方法,所以您可以将“循环”序列化数据转换回对象。
此解决方案修复了用户2451227报告的接受答案问题(当o={};JSON.stringify([o,o],getCircularReplacer()))。
函数newCircularReplacer(){常量seenValues=[]返回循环替换器函数circleReplacer(键,值){if(typeof value=='object'&&value!==null&&object.keys(value).length){常量堆栈大小=参见值长度if(堆栈大小){for(设n=stackSize-1;参见nValues[n][key]!==value;--n)seenValues.pop()//清除过期的引用if(参见nValues.includes(value))返回'[Circular]'}参见值push(value)}返回值}}设o={a:1}o.b=o//循环参考控制台日志(JSON.stringify(o,newCircularReplacer())//{a:1,b:[Circular]}✅)o={}a=[o,o]//非循环参考控制台日志(JSON.stringify(a,newCircularReplacer())//[{},{}]✅)
我为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": {}
}
}
}
@RobW的答案是正确的,但这更有表现力!因为它使用了hashmap/set:
const customStringify = function (v) {
const cache = new Set();
return JSON.stringify(v, function (key, value) {
if (typeof value === 'object' && value !== null) {
if (cache.has(value)) {
// Circular reference found
try {
// If this value does not reference a parent it can be deduped
return JSON.parse(JSON.stringify(value));
}
catch (err) {
// discard key if value cannot be deduped
return;
}
}
// Store value in our set
cache.add(value);
}
return value;
});
};