JSON stringifica un Set


99

Come farebbe un JSON.stringify () a Set ?

Cose che non funzionavano in Chromium 43:

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

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

Mi aspetterei di ottenere qualcosa di simile a quello di un array serializzato.

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

Risposte:


105

JSON.stringify non funziona direttamente con i set perché i dati memorizzati nel set non vengono memorizzati come proprietà.

Ma puoi convertire il set in un array. Quindi sarai in grado di stringerlo correttamente.

Qualsiasi delle seguenti operazioni farà il trucco:

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
Stavo per proporre Array.from(). Ma questo sembra idiomicamente migliore.
TaoPR

3
Solo per aggiungere qualche riferimento, MDN ha alcuni esempi di questa e di altre tecniche correlate
Amit

5
Potrebbe funzionare anche una comprensione dell'elenco:JSON.stringify([_ for (_ of s)])
Whymarrh

1
Tutti ottimi modi per farlo, purtroppo non funzionano in Chromium 43 out of the box come spread e Array.from non sono ancora implementati. Sembra Babele in soccorso.
MitMaro

2
Una proposta attuale per migliorare l'impostazione predefinita di Set.prototype.toJSON: github.com/DavidBruant/Map-Set.prototype.toJSON
Oncle Tom

34

Usa questo JSON.stringify sostituto:

(poiché toJSONè un artefatto legacy e un approccio migliore consiste nell'usarne uno personalizzatoreplacer , vedere 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;
}

Poi:

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

Risultato:

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

5
c'è una versione abbreviata in ES6JSON.stringify(fooBar, (key, value) => value instanceof Set ? [...value] : value)
OzzyCzech

Il reviver corrispondente è lasciato come esercizio per il lettore? ;-)
Robert Siemer

7

Sebbene tutto quanto sopra funziona, ti suggerisco di impostare una sottoclasse e aggiungere un file toJSON metodo per assicurarti che stringa correttamente. Soprattutto se stringerai spesso. Uso i set nei miei negozi Redux e avevo bisogno di assicurarmi che questo non fosse mai un problema.

Questa è un'implementazione di base. La denominazione è solo per illustrare il punto scegli il tuo stile.

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

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

4
Non consiglierei questo approccio in quanto toJSONè considerato una funzionalità legacy. Una proposta da aggiungere toJSONa entrambi seted è mapstata rifiutata: github.com/DavidBruant/Map-Set.prototype.toJSON/issues/16
MitMaro

L'override constructornon è necessario.
Justin Johnson
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.