JSON stringifiziert einen Satz

97

Wie würde ein JSON.stringify () ein Set ?

Dinge, die in Chromium 43 nicht funktionierten:

var s = new Set(['foo', 'bar']);

JSON.stringify(s); // -> "{}"
JSON.stringify(s.values()); // -> "{}"
JSON.stringify(s.keys()); // -> "{}"

Ich würde erwarten, etwas Ähnliches wie ein serialisiertes Array zu bekommen.

JSON.stringify(["foo", "bar"]); // -> "["foo","bar"]"
MitMaro
quelle

Antworten:

104

JSON.stringify funktioniert nicht direkt mit Sets, da die im Set gespeicherten Daten nicht als Eigenschaften gespeichert werden.

Sie können das Set jedoch in ein Array konvertieren. Dann können Sie es richtig stringifizieren.

Eine der folgenden Möglichkeiten reicht aus:

JSON.stringify([...s]);
JSON.stringify([...s.keys()]);
JSON.stringify([...s.values()]);
JSON.stringify(Array.from(s));
JSON.stringify(Array.from(s.keys()));
JSON.stringify(Array.from(s.values()));
Oriol
quelle
2
Ich wollte vorschlagen Array.from(). Das sieht aber idiomisch besser aus.
TaoPR
3
Nur um eine Referenz hinzuzufügen MDN hat einige Beispiele für diese und andere verwandte Techniken
Amit
5
Ein Listenverständnis könnte auch funktionieren:JSON.stringify([_ for (_ of s)])
Whymarrh
1
Alle großartigen Möglichkeiten, leider funktionieren sie in Chromium 43 nicht sofort, da Spread und Array.from noch nicht implementiert sind. Sieht aus wie Babel zur Rettung.
MitMaro
2
Ein aktueller Vorschlag zur Verbesserung der Standardeinstellung von Set.prototype.toJSON: github.com/DavidBruant/Map-Set.prototype.toJSON
Oncle Tom
34

Verwenden Sie diesen JSON.stringifyErsatz:

(Da toJSONes sich um ein altes Artefakt handelt und ein besserer Ansatz darin besteht, ein benutzerdefiniertes Artefakt zu verwendenreplacer , siehe https://github.com/DavidBruant/Map-Set.prototype.toJSON/issues/16 )

function Set_toJSON(key, value) {
  if (typeof value === 'object' && value instanceof Set) {
    return [...value];
  }
  return value;
}

Dann:

const fooBar = { foo: new Set([1, 2, 3]), bar: new Set([4, 5, 6]) };
JSON.stringify(fooBar, Set_toJSON)

Ergebnis:

"{"foo":[1,2,3],"bar":[4,5,6]}"
tanguy_k
quelle
5
Es gibt eine verkürzte Version in ES6JSON.stringify(fooBar, (key, value) => value instanceof Set ? [...value] : value)
OzzyCzech
Der entsprechende Reviver bleibt als Übung für den Leser? ;-)
Robert Siemer
7

Während all die oben genannten Arbeiten, schlage ich vor, dass Sie eine Unterklasse festlegen und eine toJSONMethode hinzufügen , um sicherzustellen, dass die Zeichenfolge korrekt ist. Vor allem, wenn Sie häufig fädeln werden. Ich verwende Sets in meinen Redux-Filialen und musste sicherstellen, dass dies nie ein Problem war.

Dies ist eine grundlegende Implementierung. Die Benennung dient nur zur Veranschaulichung des Punktes, bei dem Sie Ihren eigenen Stil auswählen.

class JSONSet extends Set {
    toJSON () {
        return [...this]
    }
}

const set = new JSONSet([1, 2, 3])
console.log(JSON.stringify(set))
Stephen Bolton
quelle
4
Ich würde diesen Ansatz nicht empfehlen, da er toJSONals Legacy-Funktion angesehen wird. Ein Vorschlag hinzufügen , toJSONum beide setund mapwurde abgelehnt: github.com/DavidBruant/Map-Set.prototype.toJSON/issues/16
MitMaro
Überschreiben constructorist nicht erforderlich.
Justin Johnson