将具有循环引用的JavaScript对象string化(转换为JSON)
我有一个包含循环引用的JavaScript对象定义:它有一个引用父对象的属性。
它也有我不想传递给服务器的function。 我将如何序列化和反序列化这些对象?
我读过最好的方法是使用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)); } }
这是我为这个问题创build的一个testing用例。 这段代码中有错误,但实质上我有对象内的对象,并传递给每个对象的引用,以显示对象创build时的父对象。 每个对象还包含函数,我不希望string化。 我只想要像Person.Name
这样的属性。
在发送到服务器之前,如何序列化并假定传回相同的JSON,将其反序列化?
如果直接( a -> a
)或间接( a -> b -> a
)是对象本身的属性,则会发生圆形结构错误。
为了避免出现错误消息,请告诉JSON.stringify当遇到循环引用时要执行的操作。 例如,如果您有一个人指向可能(或可能不会)指向原始人的另一个人(“父母”),请执行以下操作:
JSON.stringify( that.person, function( key, value) { if( key == 'parent') { return value.id;} else {return value;} })
stringify
的第二个参数是一个filter函数 。 在这里,它只是将引用的对象转换为它的ID,但是你可以自由地做任何你喜欢的事情来打破循环引用。
您可以使用以下方法testing上述代码:
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; }; });
顺便说一句,我会select一个不同的属性名称“ parent
”,因为它是一个保留字在很多语言(和DOM)。 这往往会造成混乱
看来dojo可以用JSON表示循环引用: {"id":"1","me":{"$ref":"1"}}
这里是一个例子:
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不能表示循环引用
我find了两个合适的模块来处理JSON中的循环引用。
- CircularJSON https://github.com/WebReflection/circular-json,其输出可用作;.parse()的input。 它也适用于浏览器和Node.js另请参阅: http : //webreflection.blogspot.com.au/2013/03/solving-cycles-recursions-and-circulars.html
- Isaacs json-stringify-safe https://github.com/isaacs/json-stringify-safe这可能更可读,但不能用于;.parse,只能用于Node.js
这些都应该满足您的需求。
发生在这个线程,因为我需要logging复杂的对象到一个页面,因为远程debugging是不可能在我的特定情况。 发现道格拉斯·克罗克福德(JSON的inceptor)自己的cycle.js,注释循环引用作为string,使他们可以在parsing后重新连接。 解除循环的深拷贝是安全的通过JSON.stringify。 请享用!
https://github.com/douglascrockford/JSON-js
cycle.js:这个文件包含两个函数,JSON.decycle和JSON.retrocycle,它们可以用JSON编码循环结构和标记,然后恢复它们。 这是ES5不提供的function。 JSONPath用来表示链接。
我使用以下来消除循环引用:
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));