2012-05-01 28 views
48

我有一个包含循环引用的JavaScript对象定义:它有一个引用父对象的属性。将带有循环引用的JavaScript对象Stringify(转换为JSON)

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

我读过这样做的最好方法就是使用Douglas Crockford的stringify。但是,我得到的Chrome以下错误:

TypeError: Converting circular structure to 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?

回答

90

圆形结构,当你有它是对象本身直接(a -> a)或间接的对象的属性发生误差(a -> b -> a) 。

要避免该错误消息,请告知JSON.stringify遇到循环引用时该如何处理。 例如,如果您有指向另一人(“母公司”),这可能(也可能不会)指向原来的人一个人,请执行以下操作:

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

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)。这往往会导致混乱...

9

似乎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方法对这些循环引用的对象进行反序列化。

其他资源:

How to serialize DOM node to JSON even if there are circular references?

JSON.stringify can't represent circular references

+0

嗨,谢谢你的回答。我应该说我正在使用jquery作为我的库。我当时并不认为这是相关的,我更新了我的文章。 – user1012500

+0

@ user1012500 - Dojo与jQuery一起工作良好。我经常包含其他库或框架来弥补我的主要框架中的缺陷。你甚至可以提取'toJson'和'fromJson'方法并在它们周围创建你自己的jQuery包装器。这样你就不需要拉动整个框架。不幸的是,jQuery没有开箱即用,JSON.stringify无法处理这些类型的对象。所以除了上面的例子,你可能必须自己编写这个功能。 –

+1

嗨布兰登,我很犹豫要添加另一个库来解决这个问题,因为它增加了另一个足迹。但是,我给了道场一枪,并试图用你的例子对付我的例子。然而,我遇到了循环引用问题(我没有太多的dojo知识,所以我只是尝试了一些东西,但主要基于你的例子):http://jsfiddle.net/Af3d6/1/ – user1012500

4

我找到了两个合适的模块来处理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. 伊萨克JSON-字符串化安全https://github.com/isaacs/json-stringify-safe这可能更具可读性,但不能用于.parse和仅适用于Node.js的

这些都应该满足您的需求。

-9

我用下面消除循环引用:

JS.dropClasses = function(o) { 

    for (var p in o) { 
     if (o[p] instanceof jQuery || o[p] instanceof HTMLElement) { 
      o[p] = null; 
     }  
     else if (typeof o[p] == 'object') 
      JS.dropClasses(o[p]); 
    } 
}; 

JSON.stringify(JS.dropClasses(e)); 
+2

这将删除'jQuery'和'HTMLElement'的实例,而不是循环引用? – ZachB

+0

@ZachB @ZachB我认为在他的设置中这些对他来说是圆形的......但问题是,因为JavaScript是使用的语言并不意味着我们有jQuery或甚至HTML元素。 – moeiscool

0

偶然发现这个线程,因为我需要复杂的对象登录到一个页面,因为远程调试在我的特定情况下是不可能的。找到道格拉斯克罗克福德(JSON的inceptor)自己的cycle.js,它将循环引用注释为字符串,以便在解析后重新连接它们。解除循环的深层副本可以安全地通过JSON.stringify。请享用!

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

cycle.js:此文件包含两个功能,JSON.decycle和 JSON.retrocycle,这使得它能够编码周期性结构 和DAGs的JSON,并再恢复它们。这是ES5不提供的功能。 JSONPath用于表示链接。

相关问题