JSON stringify un ensemble


102

Comment un JSON.stringify () serait-il un ensemble ?

Choses qui ne fonctionnaient pas dans Chromium 43:

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

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

Je m'attendrais à obtenir quelque chose de similaire à celui d'un tableau sérialisé.

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

Réponses:


108

JSON.stringify ne fonctionne pas directement avec les ensembles car les données stockées dans l'ensemble ne sont pas stockées en tant que propriétés.

Mais vous pouvez convertir l'ensemble en tableau. Ensuite, vous pourrez le stringifier correctement.

N'importe lequel des éléments suivants fera l'affaire:

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

2
J'allais proposer Array.from(). Mais cela semble mieux idiomiquement.
TaoPR

3
Juste pour ajouter quelques références, MDN a quelques exemples de cette technique et d'autres techniques connexes
Amit

5
Une compréhension de liste pourrait également fonctionner:JSON.stringify([_ for (_ of s)])
Whymarrh

1
Toutes les bonnes façons de le faire, malheureusement, elles ne fonctionnent pas dans Chromium 43 hors de la boîte car spread et Array.from ne sont pas encore implémentés. On dirait Babel à la rescousse.
MitMaro du

2
Une proposition actuelle pour améliorer la valeur par défaut de Set.prototype.toJSON: github.com/DavidBruant/Map-Set.prototype.toJSON
Oncle Tom

34

Utilisez ce JSON.stringifyremplaçant:

(car il toJSONs'agit d'un artefact hérité et une meilleure approche consiste à utiliser une personnalisationreplacer , voir 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;
}

Ensuite:

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

Résultat:

"{"foo":[1,2,3],"bar":[4,5,6]}"

5
il y a une version raccourcie dans ES6JSON.stringify(fooBar, (key, value) => value instanceof Set ? [...value] : value)
OzzyCzech

Le reviveur correspondant est laissé comme exercice pour le lecteur? ;-)
Robert Siemer

7

Bien que tout ce qui précède fonctionne, je suggère que vous définissiez une sous-classe et ajoutiez un toJSON méthode pour vous assurer qu'elle est correctement stringifiée. Surtout si vous allez être souvent contraignant. J'utilise des sets dans mes magasins Redux et je devais m'assurer que ce n'était jamais un problème.

Ceci est une implémentation de base. Le nommage est juste pour illustrer le point de choisir votre propre style.

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

const set = new JSONSet([1, 2, 3])
console.log(JSON.stringify(set))

4
Je ne recommanderais pas cette approche car elle toJSONest considérée comme une fonctionnalité héritée. Une proposition d'ajout toJSONaux deux setet a mapété rejetée: github.com/DavidBruant/Map-Set.prototype.toJSON/issues/16
MitMaro

Le remplacement constructorn'est pas nécessaire.
Justin Johnson
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.