2012-05-01 10 views
48
)

zu einem JSON konvertieren. Ich habe eine JavaScript-Objektdefinition, die einen Zirkelverweis enthält: Sie hat eine Eigenschaft, die auf das Elternobjekt verweist.Ein JavaScript-Objekt mit Zirkelverweis (

Es hat auch Funktionen, die ich nicht an den Server übergeben werden soll. Wie würde ich diese Objekte serialisieren und deserialisieren?

Ich habe gelesen, dass die beste Methode, dies zu tun ist, Douglas Crockfords stringify verwenden. Aber ich bin immer die folgenden Fehler in Chrome:

TypeError: Converting circular structure to JSON 

Der Code:

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)); 
    } 
} 

Dies ist ein Testfall, dass ich für diese Frage erstellt. Es gibt Fehler in diesem Code, aber im Wesentlichen habe ich Objekte innerhalb von Objekten und eine Referenz, die an jedes Objekt übergeben wird, um zu zeigen, was das übergeordnete Objekt ist, wenn das Objekt erstellt wird. Jedes Objekt enthält auch Funktionen, die nicht mit einem String versehen werden sollen. Ich möchte nur die Eigenschaften wie die Person.Name.

Wie serialisiere ich vor dem Senden an den Server und deserialize es unter der Annahme, dass das gleiche JSON zurückgegeben wird?

Antwort

90

Kreisstruktur Fehler tritt auf, wenn Sie eine Eigenschaft des Objekts haben, die das Objekt selbst direkt (a -> a) oder indirekt (a -> b -> a) .

Um die Fehlermeldung zu vermeiden, teilen Sie JSON.stringify mit, was zu tun ist, wenn es auf einen Zirkelverweis stößt. Zum Beispiel, wenn Sie eine Person haben auf eine andere Person zeigen („parent“), die auf die ursprüngliche Person Punkt (oder auch nicht) können Sie wie folgt vor:

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

Der zweite Parameter zu stringify a Filterfunktion. Hier konvertiert es einfach das referenzierte Objekt in seine ID, aber Sie können das tun, was Sie wollen, um die Zirkelreferenz zu brechen.

Sie können den obigen Code mit dem folgenden Test:

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; 
    }; 
}); 

BTW, würde ich auf „parent“ einen anderen Attributnamen wählen, da es ein reserviertes Wort in vielen Sprachen (und in DOM) ist. Dies führt zu Verwirrung auf der Straße ...

9

Es scheint, dass dojo zirkuläre Referenzen in JSON in Form darstellen kann: {"id":"1","me":{"$ref":"1"}}

Hier ein Beispiel:

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); 
});​ 

Erzeugt:

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

Hinweis: Sie können diese kreisbezogenen Objekte auch mithilfe der Methode dojox.json.ref.fromJson deserialisieren.

Weitere Ressourcen:

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

JSON.stringify can't represent circular references

+0

Hallo, danke für deine Antwort. Ich hätte sagen sollen, dass ich jquery als meine Bibliothek benutze. Ich dachte nicht, dass es zu der Zeit relevant war. Ich werde meinen Beitrag aktualisieren. – user1012500

+0

@ user1012500 - Dojo funktioniert gut neben jQuery. Ich schließe oft andere Bibliotheken oder Frameworks ein, um Mängel in meinem primären Framework auszugleichen. Sie können möglicherweise sogar die Methoden 'toJson' und' fromJson' extrahieren und einen eigenen jQuery-Wrapper um sie erstellen. Auf diese Weise müssen Sie nicht den gesamten Rahmen einbeziehen. Leider verfügt jQuery nicht über diese Funktionalität, und JSON.stringify kann diese Objekttypen nicht verarbeiten. Anders als in den obigen Beispielen müssen Sie diese Funktionalität möglicherweise selbst programmieren. –

+1

Hallo Brandon, ich zögere, eine weitere Bibliothek hinzuzufügen, um das Problem zu lösen, da es der Site einen weiteren Fußabdruck hinzufügt. Allerdings gab ich Dojo einen Schuss und versuchte, dein Beispiel gegen meinen zu verwenden. Allerdings stieß ich auf das zirkuläre Referenzproblem (ich habe nicht viel Wissen über Dojo, also habe ich nur ein paar Dinge versucht, aber hauptsächlich auf dein Beispiel bezogen): http://jsfiddle.net/Af3d6/1/ – user1012500

4

Ich habe zwei geeignete Module gefunden, um zirkuläre Referenzen in JSON zu behandeln.

  1. CircularJSON https://github.com/WebReflection/circular-json, deren Ausgabe als Eingabe für .parse() verwendet werden kann. Es funktioniert auch in Browsern & Node.js Siehe auch: http://webreflection.blogspot.com.au/2013/03/solving-cycles-recursions-and-circulars.html
  2. Isaacs json-stringify sichere https://github.com/isaacs/json-stringify-safe die vielleicht besser lesbar, aber nicht für .parse verwendet werden und für Node.js nur verfügbar ist,

Beide sollten Ihren Bedürfnissen entsprechen.

-9

habe ich die im Anschluss an die zirkuläre Verweise zu beseitigen:

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

Dadurch werden Instanzen von 'jQuery' und' HTMLElement' entfernt, keine Zirkelverweise? – ZachB

+0

@ZachB Ich denke in seinem Setup sind diese für ihn kreisförmig ... aber das Problem ist, dass gerade weil Javascript die verwendete Sprache nicht bedeutet, dass wir jquery oder sogar HTML-Elemente haben. – moeiscool

0

auf diesen Thread geschah, weil ich auf eine Seite, komplexe Objekte zu protokollieren benötigt, da Remote-Debugging in meiner besonderen Situation nicht möglich war. Gefunden Douglas Crockfords (Inzeptor von JSON) eigene cycle.js, die kreisförmige Referenzen als Strings annotieren, so dass sie nach dem Parsen wieder verbunden werden können. Die decycelte tiefe Kopie kann sicher durch JSON.stringify geleitet werden. Genießen!

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

cycle.js: Diese Datei enthält zwei Funktionen, JSON.decycle und JSON.retrocycle, die es ermöglicht, zyklische Strukturen und dags in JSON zu kodieren und sie dann zu erholen. Dies ist eine Funktion, die nicht von ES5 bereitgestellt wird. JSONPath wird zur Darstellung der Links verwendet.

Verwandte Themen