2012-05-01 26 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用於表示鏈接。

相關問題