Ich habe eine JavaScript-Objektdefinition, die einen Zirkelverweis enthält: Sie hat eine Eigenschaft, die auf das übergeordnete Objekt verweist.
Es hat auch Funktionen, die ich nicht an den Server weitergeben möchte. Wie würde ich diese Objekte serialisieren und deserialisieren?
Ich habe gelesen, dass die beste Methode dazu die Verwendung von Douglas Crockfords Stringify ist. In Chrome wird jedoch der folgende Fehler angezeigt:
TypeError: Konvertieren einer Kreisstruktur in 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, den ich für diese Frage erstellt habe. Es gibt Fehler in diesem Code, aber im Wesentlichen habe ich Objekte in 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 ich nicht stringifizieren möchte. Ich möchte nur die Eigenschaften wie die Person.Name
.
Wie serialisiere ich vor dem Senden an den Server und deserialisiere ihn unter der Annahme, dass derselbe JSON zurückgegeben wird?
quelle
replacer
in Ihremstringify
Anruf zu verwenden, wie @MattEvans unten hervorhebt .Antworten:
Kreisstrukturfehler treten auf, wenn Sie eine Eigenschaft des Objekts haben, die das Objekt selbst direkt (
a -> a
) oder indirekt (a -> b -> a
) ist.Um die Fehlermeldung zu vermeiden, teilen Sie JSON.stringify mit, was zu tun ist, wenn ein Zirkelverweis auftritt. Wenn Sie beispielsweise eine Person haben, die auf eine andere Person ("Elternteil") zeigt, die möglicherweise auf die ursprüngliche Person verweist (oder nicht), gehen Sie wie folgt vor:
JSON.stringify( that.person, function( key, value) { if( key == 'parent') { return value.id;} else {return value;} })
Der zweite Parameter
stringify
ist eine Filterfunktion . Hier konvertiert es einfach das referenzierte Objekt in seine ID, aber Sie können tun, was Sie möchten, um die Zirkelreferenz zu brechen.Sie können den obigen Code folgendermaßen testen:
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; }; });
Übrigens würde ich einen anderen Attributnamen als "
parent
" wählen, da es sich in vielen Sprachen (und in DOM) um ein reserviertes Wort handelt. Dies führt zu Verwirrung auf der Straße ...quelle
parent
?owner
wird normalerweise anstelle von verwendetparent
.Es scheint, dass Dojo Zirkelverweise in JSON in folgender Form darstellen kann:
{"id":"1","me":{"$ref":"1"}}
Hier ist 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); });
Produziert:
{ "name":"Kris", "father":{ "name":"Bill", "wife":{ "name":"Karen" } }, "mother":{ "$ref":"#father.wife" } }
Hinweis: Mit dieser
dojox.json.ref.fromJson
Methode können Sie diese Objekte, auf die mit Zirkel verwiesen wird, auch de-serialisieren .Andere Ressourcen:
Wie serialisiere ich einen DOM-Knoten in JSON, auch wenn Zirkelverweise vorhanden sind?
JSON.stringify kann keine Zirkelverweise darstellen
quelle
toJson
undfromJson
Methoden und um sie Ihren eigenen jQuery - Wrapper zu erstellen. Auf diese Weise müssen Sie nicht das gesamte Framework einbeziehen. Leider verfügt jQuery nicht über diese sofort einsatzbereite Funktionalität, und JSON.stringify kann diese Objekttypen nicht verarbeiten. Abgesehen von den obigen Beispielen müssen Sie diese Funktionalität möglicherweise selbst codieren.Ich habe zwei geeignete Module gefunden, um Zirkelverweise in JSON zu verarbeiten.
Beides sollte Ihren Anforderungen entsprechen.
quelle
Dies geschah in diesem Thread, weil ich komplexe Objekte auf einer Seite protokollieren musste, da Remote-Debugging in meiner speziellen Situation nicht möglich war. Es wurde Douglas Crockfords (Inceptor von JSON) eigenes cycle.js gefunden, das Zirkelverweise als Zeichenfolgen kommentiert, sodass sie nach dem Parsen wieder verbunden werden können. Die entzyklierte tiefe Kopie kann sicher durch JSON.stringify geleitet werden. Genießen!
https://github.com/douglascrockford/JSON-js
quelle
No-lib
Verwenden Sie den folgenden Ersetzer , um json mit Zeichenfolgenreferenzen (ähnlicher json-Pfad ) zu generieren , um Objekte zu duplizieren, auf die verwiesen wird
let s = JSON.stringify(obj, refReplacer());
Code-Snippet anzeigen
function refReplacer() { let m = new Map(), v= new Map(), init = null; return function(field, value) { let p= m.get(this) + (Array.isArray(this) ? `[${field}]` : '.' + field); let isComplex= value===Object(value) if (isComplex) m.set(value, p); let pp = v.get(value)||''; let path = p.replace(/undefined\.\.?/,''); let val = pp ? `#REF:${pp[0]=='[' ? '$':'$.'}${pp}` : value; !init ? (init=value) : (val===init ? val="#REF:$" : 0); if(!pp && isComplex) v.set(value, path); return val; } } // --------------- // TEST // --------------- // gen obj with duplicate references let a = { a1: 1, a2: 2 }; let b = { b1: 3, b2: "4" }; let obj = { o1: { o2: a }, b, a }; // duplicate reference a.a3 = [1,2,b]; // circular reference b.b3 = a; // circular reference let s = JSON.stringify(obj, refReplacer(), 4); console.log(s);
Und folgende Parser-Funktion, um ein Objekt aus einem solchen "ref-json" neu zu generieren
Code-Snippet anzeigen
function parseRefJSON(json) { let objToPath = new Map(); let pathToObj = new Map(); let o = JSON.parse(json); let traverse = (parent, field) => { let obj = parent; let path = '#REF:$'; if (field !== undefined) { obj = parent[field]; path = objToPath.get(parent) + (Array.isArray(parent) ? `[${field}]` : `${field?'.'+field:''}`); } objToPath.set(obj, path); pathToObj.set(path, obj); let ref = pathToObj.get(obj); if (ref) parent[field] = ref; for (let f in obj) if (obj === Object(obj)) traverse(obj, f); } traverse(o); return o; } // ------------ // TEST // ------------ let s = `{ "o1": { "o2": { "a1": 1, "a2": 2, "a3": [ 1, 2, { "b1": 3, "b2": "4", "b3": "#REF:$.o1.o2" } ] } }, "b": "#REF:$.o1.o2.a3[2]", "a": "#REF:$.o1.o2" }`; console.log('Open Chrome console to see nested fields:'); let obj = parseRefJSON(s); console.log(obj);
quelle
Ich habe Folgendes verwendet, um die Zirkelverweise zu entfernen:
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));
quelle
jQuery
undHTMLElement
nicht Zirkelverweise entfernt.