我有一个大对象要转换成JSON并发送。然而,它具有圆形结构。我想丢弃任何存在的循环引用,并发送任何可以字符串化的引用。我该怎么做?
谢谢
var obj = {
a: "foo",
b: obj
}
我想将对象字符串化为:
{"a":"foo"}
我有一个大对象要转换成JSON并发送。然而,它具有圆形结构。我想丢弃任何存在的循环引用,并发送任何可以字符串化的引用。我该怎么做?
谢谢
var obj = {
a: "foo",
b: obj
}
我想将对象字符串化为:
{"a":"foo"}
当前回答
我真的很喜欢Trindaz的解决方案——更详细,但它有一些缺陷。我也为喜欢它的人修过。
此外,我对缓存对象添加了长度限制。
如果我打印的对象真的很大-我的意思是无限大-我想限制我的算法。
JSON.stringifyOnce = function(obj, replacer, indent){
var printedObjects = [];
var printedObjectKeys = [];
function printOnceReplacer(key, value){
if ( printedObjects.length > 2000){ // browsers will not print more than 20K, I don't see the point to allow 2K.. algorithm will not be fast anyway if we have too many objects
return 'object too long';
}
var printedObjIndex = false;
printedObjects.forEach(function(obj, index){
if(obj===value){
printedObjIndex = index;
}
});
if ( key == ''){ //root element
printedObjects.push(obj);
printedObjectKeys.push("root");
return value;
}
else if(printedObjIndex+"" != "false" && typeof(value)=="object"){
if ( printedObjectKeys[printedObjIndex] == "root"){
return "(pointer to root)";
}else{
return "(see " + ((!!value && !!value.constructor) ? value.constructor.name.toLowerCase() : typeof(value)) + " with key " + printedObjectKeys[printedObjIndex] + ")";
}
}else{
var qualifiedKey = key || "(empty key)";
printedObjects.push(value);
printedObjectKeys.push(qualifiedKey);
if(replacer){
return replacer(key, value);
}else{
return value;
}
}
}
return JSON.stringify(obj, printOnceReplacer, indent);
};
其他回答
我真的很喜欢Trindaz的解决方案——更详细,但它有一些缺陷。我也为喜欢它的人修过。
此外,我对缓存对象添加了长度限制。
如果我打印的对象真的很大-我的意思是无限大-我想限制我的算法。
JSON.stringifyOnce = function(obj, replacer, indent){
var printedObjects = [];
var printedObjectKeys = [];
function printOnceReplacer(key, value){
if ( printedObjects.length > 2000){ // browsers will not print more than 20K, I don't see the point to allow 2K.. algorithm will not be fast anyway if we have too many objects
return 'object too long';
}
var printedObjIndex = false;
printedObjects.forEach(function(obj, index){
if(obj===value){
printedObjIndex = index;
}
});
if ( key == ''){ //root element
printedObjects.push(obj);
printedObjectKeys.push("root");
return value;
}
else if(printedObjIndex+"" != "false" && typeof(value)=="object"){
if ( printedObjectKeys[printedObjIndex] == "root"){
return "(pointer to root)";
}else{
return "(see " + ((!!value && !!value.constructor) ? value.constructor.name.toLowerCase() : typeof(value)) + " with key " + printedObjectKeys[printedObjIndex] + ")";
}
}else{
var qualifiedKey = key || "(empty key)";
printedObjects.push(value);
printedObjectKeys.push(qualifiedKey);
if(replacer){
return replacer(key, value);
}else{
return value;
}
}
}
return JSON.stringify(obj, printOnceReplacer, indent);
};
@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;
});
};
我想知道为什么还没有人从MDN页面发布正确的解决方案。。。
const circular Reference={otherData:123};circular Reference.imy=circular参考;常量getCircularReplacer=()=>{const seed=new WeakSet();return(键,值)=>{if(typeof value==“object”&&value!==null){if(seed.has(value)){回来}见add(值);}返回值;};};const stringified=JSON.stringify(circularReference,getCircularReplacer());console.log(字符串化);
Seen值应该存储在集合中,而不是数组中(每个元素都会调用replacer)。
与公认的答案一样,此解决方案删除了所有重复值,而不仅仅是循环值。但至少它没有指数级的复杂性。
我为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": {}
}
}
}
使用此类对象解决此问题的另一种解决方案是使用此库
https://github.com/ericmuyser/stringy
它很简单,你可以在几个简单的步骤中解决这个问题。