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

谢谢

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

我想将对象字符串化为:

{"a":"foo"}

当前回答

我为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": {}
    }
  }
}

其他回答

就这样吧

npm i --save circular-json

然后在js文件中

const CircularJSON = require('circular-json');
...
const json = CircularJSON.stringify(obj);

https://github.com/WebReflection/circular-json

注意:我与这个包裹无关。但我确实用它来做这个。

2020年更新

请注意,CircularJSON仅在维护中,flatted是其继任者。

我建议从@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()来自定义净化行为。如果您发现自己需要一个简单的示例来说明如何做到这一点,我只是在这里编写了一个自定义替换器,它将错误、正则表达式和函数强制转换为人类可读的字符串。

当你不知道所有循环引用的键时,对于未来搜索这个问题解决方案的谷歌用户,你可以使用JSON.stringify函数的包装器来排除循环引用。参见示例脚本https://gist.github.com/4653128.

解决方案本质上归结为在数组中保留对先前打印对象的引用,并在返回值之前在替换函数中检查该引用。它比仅排除循环引用更具限制性,因为它还排除了两次打印对象的可能性,其副作用之一是避免循环引用。

包装示例:

function stringifyOnce(obj, replacer, indent){
    var printedObjects = [];
    var printedObjectKeys = [];

    function printOnceReplacer(key, value){
        var printedObjIndex = false;
        printedObjects.forEach(function(obj, index){
            if(obj===value){
                printedObjIndex = index;
            }
        });

        if(printedObjIndex && typeof(value)=="object"){
            return "(see " + value.constructor.name.toLowerCase() + " 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);
}

试试看:

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

var circular_replacer = (value) => {
    var seen = [];
    if (value != null && typeof value == "object") {
        if (seen.indexOf(value) >= 0) return;
        seen.push(value);
    }
    return value;
};

obj = circular_replacer(obj);

JSON.stringify()的第二个参数还允许您指定一个关键字名称数组,该数组应保存在数据中遇到的每个对象中。这可能不适用于所有用例,但却是一个简单得多的解决方案。

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify

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

var json = JSON.stringify(obj, ['a']);
console.log(json);
// {"a":"foo"}

注意:奇怪的是,OP中的对象定义在最新的Chrome或Firefox中没有抛出循环引用错误。这个答案中的定义被修改了,所以它确实抛出了一个错误。