Ich habe ein großes Objekt, das ich in JSON konvertieren und senden möchte. Es hat jedoch eine kreisförmige Struktur. Ich möchte alle vorhandenen Zirkelverweise wegwerfen und alles senden, was stringifiziert werden kann. Wie mache ich das?
Vielen Dank.
var obj = {
a: "foo",
b: obj
}
Ich möchte obj in folgende Zeichenfolge einteilen:
{"a":"foo"}
javascript
json
node.js
Harry
quelle
quelle
Antworten:
Verwendung
JSON.stringify
mit einem benutzerdefinierten Ersatz. Zum Beispiel:Der Ersetzer in diesem Beispiel ist nicht 100% korrekt (abhängig von Ihrer Definition von "Duplikat"). Im folgenden Fall wird ein Wert verworfen:
Das Konzept lautet jedoch: Verwenden Sie einen benutzerdefinierten Ersetzer und verfolgen Sie die analysierten Objektwerte.
Als Dienstprogrammfunktion in es6 geschrieben:
quelle
Node.prototype.toJSON = function() { return 'whatever you think that is right'; };
vorstellen können , können Sie versuchen, DOM-Objekten eine benutzerdefinierte Serialisierungsmethode hinzuzufügen: (Wenn Sie etwas allgemeineres / spezifischeres wünschen, versuchen Sie einfach etwas im Prototypbaum: HTMLDivElement implementiert HTMLElement-Implementierungen Element implementiert Node implementiert EventTarget; Hinweis: Dies kann browserabhängig sein, der vorherige Baum gilt für Chrome)var a={id:1}; JSON.stringify([a,a]);
cache
wird nicht erreichbar sein developer.mozilla.org/en-US/docs/Web/JavaScript/...In Node.js können Sie util.inspect (Objekt) verwenden . Es ersetzt automatisch kreisförmige Links durch "[Rundschreiben]".
Obwohl es integriert ist (keine Installation erforderlich) , müssen Sie es importieren
Um es zu benutzen, rufen Sie einfach anBeachten Sie auch, dass Sie das zu inspizierende Optionsobjekt übergeben können (siehe Link oben).
Bitte lesen Sie und geben Sie den Kommentatoren unten ein Lob ...
quelle
var util = require('util');
obj_str = util.inspect(thing)
, NICHT <s>garbage_str = JSON.stringify(util.inspect(thing))
</ s>Ich frage mich, warum noch niemand die richtige Lösung von der MDN-Seite gepostet hat ...
Gesehene Werte sollten in einer Menge gespeichert werden , nicht in einem Array (der Ersetzer wird für jedes Element aufgerufen ), und es ist nicht erforderlich,
JSON.stringify
jedes Element in der Kette zu testen , was zu einer Zirkelreferenz führt .Wie in der akzeptierten Antwort entfernt diese Lösung alle sich wiederholenden Werte , nicht nur die kreisförmigen. Aber zumindest hat es keine exponentielle Komplexität.
quelle
replacer = () => { const seen = new WeakSet(); return (key, value) => { if (typeof value === "object" && value !== null) { if (seen.has(value)) { return; } seen.add(value); } return value; }; } () => { const seen = new WeakSet(); return (key, value) => { if (typeof value === "object" && value !== null) { if (seen.has(value)) { return; } seen.add(value); … JSON.stringify({a:1, b: '2'}, replacer)
kehrtundefined
in Chrom zurückmach einfach
dann in Ihrer js-Datei
https://github.com/WebReflection/circular-json
HINWEIS: Ich habe nichts mit diesem Paket zu tun. Aber ich benutze es dafür.
Update 2020
Bitte beachten Sie, dass CircularJSON nur in Wartung ist und sein Nachfolger abgeflacht ist.
quelle
JSON
grundsätzlich zu überschreiben .Flatted.stringify({blah: 1})
Ergebnisse in[{"blah":1}]
) Ich sehe, dass jemand versucht hat, ein Problem zu diesem Thema anzusprechen, und der Autor hat sie beschimpft und das Problem für Kommentare gesperrt.Die Lösung von Trindaz hat mir sehr gut gefallen - ausführlicher, aber es gab einige Fehler. Ich habe sie für jeden repariert, der es auch mag.
Außerdem habe ich meinen Cache-Objekten eine Längenbeschränkung hinzugefügt.
Wenn das Objekt, das ich drucke, wirklich groß ist - ich meine unendlich groß - möchte ich meinen Algorithmus einschränken.
quelle
@ RobWs Antwort ist richtig, aber das ist performanter! Weil es eine Hashmap / Set verwendet:
quelle
{"a":{"b":{"a":"d"}}}
und sogar das Entfernen von Knoten mit leerem Objekt {}Beachten Sie, dass es auch eine
JSON.decycle
von Douglas Crockford implementierte Methode gibt . Siehe seine cycle.js . Auf diese Weise können Sie nahezu jede Standardstruktur stringifizieren:Sie können das ursprüngliche Objekt auch mit der
retrocycle
Methode neu erstellen . Sie müssen also keine Zyklen von Objekten entfernen, um sie zu stringifizieren.Dies funktioniert jedoch nicht für DOM-Knoten (die typische Ursachen für Zyklen in realen Anwendungsfällen sind). Zum Beispiel wird dies werfen:
Ich habe eine Gabel gemacht, um dieses Problem zu lösen (siehe meine Gabel cycle.js ). Dies sollte gut funktionieren:
Beachten Sie, dass in meiner Gabelung
JSON.decycle(variable)
wie im Original funktioniert und eine Ausnahmevariable
ausgelöst wird, wenn die DOM-Knoten / Elemente enthalten.Wenn Sie verwenden
JSON.decycle(variable, true)
, akzeptieren Sie die Tatsache, dass das Ergebnis nicht umkehrbar ist (Retrocycle erstellt keine DOM-Knoten neu). DOM-Elemente sollten jedoch bis zu einem gewissen Grad identifizierbar sein. Wenn eindiv
Element beispielsweise eine ID hat, wird es durch eine Zeichenfolge ersetzt"div#id-of-the-element"
.quelle
JSON.decycle(a, true)
Was passiert, wenn Sie true als Parameter für die Decycle-Funktion übergeben?stringifyNodes
Option in der Gabel wahr. Dies wird zBdiv
mit id = "some-id" in string :div#some-id
. Sie werden einige Probleme vermeiden, aber Sie werden nicht in der Lage sein, einen vollständigen Rückzyklus durchzuführen.Ich würde empfehlen, json-stringify-safe von @ isaacs zu überprüfen - es wird in NPM verwendet.
Installieren:
Benutzen:
Dies ergibt:
quelle
Für zukünftige Googler, die nach einer Lösung für dieses Problem suchen, wenn Sie die Schlüssel aller Zirkelverweise nicht kennen, können Sie einen Wrapper um die Funktion JSON.stringify verwenden, um Zirkelverweise auszuschließen. Ein Beispielskript finden Sie unter https://gist.github.com/4653128 .
Die Lösung besteht im Wesentlichen darin, einen Verweis auf zuvor gedruckte Objekte in einem Array beizubehalten und diesen in einer Ersetzungsfunktion zu überprüfen, bevor ein Wert zurückgegeben wird. Es ist einschränkender, als nur Zirkelverweise auszuschließen, da es auch ausschließt, dass ein Objekt jemals zweimal gedruckt wird. Eine der Nebeneffekte besteht darin, Zirkelverweise zu vermeiden.
Beispiel Wrapper:
quelle
if(printedObjIndex)
während Sie schreiben sollten,if(printedObjIndex==false)
daindex
dies auch der Fall sein kann, in0
den übersetzt wird,false
sofern Sie nicht ausdrücklich etwas anderes angeben.===
?0 == false
isttrue
,0 === false
istfalse
. ; ^) Aber ich würde lieber nichtprintedObjIndex
mit false initialisieren , da du dann dagegen prüfen kannst,undefined
dass du (na ja, Trindaz) Metaphern nicht so seltsam mischst.Verwenden Sie die JSON.stringify-Methode mit einem Ersetzer. Lesen Sie diese Dokumentation für weitere Informationen. http://msdn.microsoft.com/en-us/library/cc836459%28v=vs.94%29.aspx
Finden Sie heraus, wie Sie das Ersatzarray mit zyklischen Referenzen füllen können. Mit der typeof-Methode können Sie feststellen, ob die Eigenschaft vom Typ 'object' (Referenz) ist, und mit einer genauen Gleichheitsprüfung (===) die Zirkelreferenz überprüfen.
quelle
var obj = {foo:obj}
nicht nicht einen zirkulären Verweis erstellen. Stattdessen wird ein Objekt erstellt, dessenfoo
Attribut auf den vorherigen Wert von verweistobj
(undefined
falls nicht zuvor definiert, deklariert wegenvar obj
).Wenn
führt zu a
Dann möchten Sie vielleicht so drucken:
quelle
bewertet zu:
mit der Funktion:
quelle
Ich weiß, dass dies eine alte Frage ist, aber ich möchte ein von mir erstelltes NPM-Paket namens Smart-Circular vorschlagen , das anders funktioniert als die anderen vorgeschlagenen Methoden. Dies ist besonders nützlich, wenn Sie große und tiefe Objekte verwenden .
Einige Funktionen sind:
Ersetzen von Zirkelreferenzen oder einfach wiederholten Strukturen innerhalb des Objekts durch den Pfad, der zu seinem ersten Auftreten führt (nicht nur die Zeichenfolge [Zirkel] );
Durch die Suche nach Kreisförmigkeiten in einer Breitensuche stellt das Paket sicher, dass dieser Pfad so klein wie möglich ist. Dies ist wichtig, wenn es sich um sehr große und tiefe Objekte handelt, bei denen die Pfade ärgerlich lang und schwer zu verfolgen sein können (der benutzerdefinierte Ersatz in) JSON.stringify führt eine DFS durch);
Ermöglicht personalisierte Ersetzungen, um weniger wichtige Teile des Objekts zu vereinfachen oder zu ignorieren.
Schließlich werden die Pfade genau so geschrieben, wie es für den Zugriff auf das angegebene Feld erforderlich ist. Dies kann Ihnen beim Debuggen helfen.
quelle
Das zweite Argument für JSON.stringify () auch ermöglicht es Ihnen , eine Reihe von Schlüsselnamen angeben , die von jedem Objekt erhalten werden soll es innerhalb Ihrer Daten trifft. Dies funktioniert möglicherweise nicht für alle Anwendungsfälle, ist jedoch eine viel einfachere Lösung.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify
Hinweis: Seltsamerweise löst die Objektdefinition von OP in der neuesten Version von Chrome oder Firefox keinen Zirkelreferenzfehler aus. Die Definition in dieser Antwort wurde so modifiziert , dass es tat wirft einen Fehler.
quelle
Verwenden
circular-json
Sie nicht (es ist veraltet), um die Antwort auf das Überschreiben der Funktionsweise von JSON zu aktualisieren (wahrscheinlich nicht empfohlen, aber sehr einfach ). Verwenden Sie stattdessen den abgeflachten Nachfolger:https://www.npmjs.com/package/flatted
Aus der alten Antwort oben von @ user1541685 entlehnt, aber durch die neue ersetzt:
npm i --save flatted
dann in Ihrer js-Datei
quelle
Ich habe auf github eine Circular-Json-Bibliothek gefunden , die für mein Problem gut funktioniert hat.
Einige gute Funktionen, die ich nützlich fand:
quelle
Ich löse dieses Problem folgendermaßen:
quelle
_class: ClassName { data: "here" }
, also habe ich die folgende Regel hinzugefügt.replace(/(\w+) {/g, '{ __ClassName__: "$1", ')
. In meinem Fall habe ich versucht zu sehen, wie ein http-Anforderungsobjekt aussieht.Ich weiß, dass diese Frage alt ist und viele gute Antworten hat, aber ich poste diese Antwort wegen ihres neuen Geschmacks (es5 +).
Code-Snippet anzeigen
quelle
Obwohl dies ausreichend beantwortet wurde, können Sie die betreffende Eigenschaft auch explizit löschen, bevor Sie sie mit dem
delete
Operator stringifizieren .Operator löschen
Dadurch entfällt die Notwendigkeit, komplexe Logik zum Entfernen von Zirkelverweisen zu erstellen oder zu verwalten.
quelle
quelle
Eine andere Lösung zur Lösung dieses Problems mit solchen Objekten ist die Verwendung dieser Bibliothek
https://github.com/ericmuyser/stringy
Es ist einfach und Sie können dies in wenigen einfachen Schritten lösen.
quelle
Basierend auf den anderen Antworten erhalte ich den folgenden Code. Es funktioniert ziemlich gut mit Zirkelverweisen, Objekten mit benutzerdefinierten Konstruktoren.
Von dem gegebenen Objekt, das serialisiert werden soll,
Github Link - DecycledJSON
Beispiel Verwendung 1:
Beispiel Verwendung 2:
quelle
Versuche dies:
quelle
seen.push(value)
= -D nicht noch ein paar Codezeilen geben ? Gefälltfor (var key in value) {value[key] = circular_replacer(value[key]);}
Wenn Sie in meiner Lösung auf einen Zyklus stoßen, heißt es nicht nur "Zyklus" (oder nichts), sondern auch etwas wie foo: Siehe Objekt Nr. 42 oben, und um zu sehen, wo foo auf Sie zeigt, können Sie nach oben scrollen und suchen für Objekt # 42 (jedes Objekt sagt beim Start Objekt # xxx mit einer ganzen Zahl xxx)
Snippet:
quelle