字符串化(转换为 JSON)一个带有循环引用的 JavaScript 对象

IT技术 javascript jquery json serialization stringify
2021-02-07 22:32:33

我有一个 JavaScript 对象定义,其中包含一个循环引用:它有一个引用父对象的属性。

它还具有我不想传递到服务器的功能。我将如何序列化和反序列化这些对象?

我读过最好的方法是使用 Douglas Crockford 的 stringify。但是,我在 Chrome 中收到以下错误:

类型错误:将圆形结构转换为 JSON

代码:

function finger(xid, xparent){
    this.id = xid;
    this.xparent;
    //other attributes
}

function arm(xid, xparent){
    this.id = xid;
    this.parent = xparent;
    this.fingers = [];

    //other attributes

    this.moveArm = function() {
        //moveArm function details - not included in this testcase
        alert("moveArm Executed");
    }
}

 function person(xid, xparent, xname){
    this.id = xid;
    this.parent = xparent;
    this.name = xname
    this.arms = []

    this.createArms = function () {
        this.arms[this.arms.length] = new arm(this.id, this);
    }
}

function group(xid, xparent){
    this.id = xid;
    this.parent = xparent;
    this.people = [];
    that = this;

    this.createPerson = function () {
        this.people[this.people.length] = new person(this.people.length, this, "someName");
        //other commands
    }

    this.saveGroup = function () {
        alert(JSON.stringify(that.people));
    }
}

这是我为此问题创建的测试用例。这段代码中有错误,但本质上我在对象中有对象,并且传递给每个对象的引用以显示创建对象时父对象是什么。每个对象还包含函数,我不想对其进行字符串化。我只想要诸如Person.Name.

假设传递回相同的 JSON,如何在发送到服务器之前进行序列化并反序列化它?

6个回答

当您拥有对象的属性即对象本身直接 ( a -> a) 或间接 ( a -> b -> a)时,会发生循环结构错误

为避免出现错误消息,请告诉 JSON.stringify 在遇到循环引用时要执行的操作。例如,如果您有一个人指向另一个人(“父母”),该人可能(也可能不)指向原来的人,请执行以下操作:

JSON.stringify( that.person, function( key, value) {
  if( key == 'parent') { return value.id;}
  else {return value;}
})

to的第二个参数stringify是一个过滤函数在这里,它只是将引用的对象转换为其 ID,但您可以随意破坏循环引用。

您可以使用以下代码测试上述代码:

function Person( params) {
  this.id = params['id'];
  this.name = params['name']; 
  this.father = null;
  this.fingers = [];
  // etc.
}

var me = new Person({ id: 1, name: 'Luke'});
var him = new Person( { id:2, name: 'Darth Vader'});
me.father = him; 
JSON.stringify(me); // so far so good

him.father = me; // time travel assumed :-)
JSON.stringify(me); // "TypeError: Converting circular structure to JSON"
// But this should do the job:
JSON.stringify(me, function( key, value) {
  if(key == 'father') { 
    return value.id;
  } else {
    return value;
  };
});

顺便说一句,我会为“ parent选择一个不同的属性名称,因为它是许多语言(以及 DOM)中的保留字。这往往会导致混乱......

@Esqarrouthowner通常用于代替parent.
2021-03-18 22:32:33
我们应该parent什么来改变变量
2021-04-06 22:32:33

看来dojo可以以 JSON 的形式表示循环引用:{"id":"1","me":{"$ref":"1"}}

下面是一个例子:

http://jsfiddle.net/dumeG/

require(["dojox/json/ref"], function(){
    var me = {
        name:"Kris",
        father:{name:"Bill"},
        mother:{name:"Karen"}
    };
    me.father.wife = me.mother;
    var jsonMe = dojox.json.ref.toJson(me); // serialize me
    alert(jsonMe);
});​

产生:

{
   "name":"Kris",
   "father":{
     "name":"Bill",
     "wife":{
          "name":"Karen"
      }
   },
   "mother":{
     "$ref":"#father.wife"
   }
}

注意:您还可以使用dojox.json.ref.fromJson方法反序列化这些循环引用的对象

其他资源:

即使有循环引用,如何将 DOM 节点序列化为 JSON?

JSON.stringify 不能代表循环引用

Dojo 的 ref module设法像微风一样对我的模型进行字符串化/解析。在我的场景中,来自 crockford 的 cycle.js 库没有成功,因为我使用 newtonsoft json.net 来序列化 C# 对象并且它不使用 jsonpath(就像 cycle.js 使用的那样)。看起来不错的老道场拯救了我的一天!感谢您的回答。
2021-03-14 22:32:33
不要与JavaScript 对象文本混淆,JSON不能包含函数,因为它是一种数据交换格式(如 XML)。因此,为了序列化为 JSON 格式,您需要一个兼容的对象字面量。此示例将您的示例修改为兼容(尽管它可能不是您想要的,因为您不再使用对象实例)。即使您删除了 toJSON 函数,对底层原型函数的引用仍然使其无效。
2021-03-19 22:32:33
您好,感谢您的回答。我应该声明我使用 jquery 作为我的库。我当时认为这无关紧要。请更新我的帖子。
2021-03-26 22:32:33
@user1012500 - Dojo 与 jQuery 一起工作得很好。我经常包含其他库或框架来弥补我的主要框架中的缺陷。您甚至可以提取toJsonfromJson方法并围绕它们创建自己的 jQuery 包装器。这样你就不需要拉入整个框架。不幸的是,jQuery 没有开箱即用的功能,而且 JSON.stringify 无法处理这些类型的对象。因此,除了上述示例之外,您可能必须自己编写此功能的代码。
2021-03-28 22:32:33
嗨,布兰登,我很犹豫要不要添加另一个库来解决这个问题,因为它为站点增加了另一个足迹。然而,我给了道场一个机会,并试图用你的例子来对抗我的。但是,我遇到了循环引用问题(我对 dojo 了解不多,所以我只是尝试了几件事,但主要基于您的示例):jsfiddle.net/Af3d6/1
2021-04-01 22:32:33

无库

下面使用代用品,以产生与JSON字符串的引用(类似于JSON路径)复制/圆形的被引用对象

let s = JSON.stringify(obj, refReplacer());

并遵循解析器函数从这样的“ref-json”重新生成对象

这很棒....
2021-04-04 22:32:33

我找到了两个合适的module来处理 JSON 中的循环引用。

  1. CircularJSON https://github.com/WebReflection/circular-json,其输出可用作 .parse() 的输入。它也适用于浏览器和 Node.js 另请参阅:http : //webreflection.blogspot.com.au/2013/03/solving-cycles-recursions-and-circulars.html
  2. Isaacs json-stringify-safe https://github.com/isaacs/json-stringify-safe这可能更具可读性,但不能用于 .parse 并且仅适用于 Node.js

其中任何一个都应该满足您的需求。

发生在这个线程上是因为我需要将复杂的对象记录到页面,因为在我的特定情况下无法进行远程调试。找到了 Douglas Crockford(JSON 的接收者)自己的 cycle.js,它将循环引用注释为字符串,以便它们在解析后可以重新连接。去循环的深层副本可以安全地通过 JSON.stringify。享受!

https://github.com/douglascrockford/JSON-js

cycle.js:这个文件包含两个函数,JSON.decycle 和 JSON.retrocycle,这使得可以在 JSON 中编码循环结构和 dag,然后恢复它们。这是 ES5 没有提供的能力。JSONPath 用于表示链接。