JSON stringify a Set

109

W jaki sposób jeden JSON.stringify () do zestawu ?

Rzeczy, które nie działały w Chromium 43:

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

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

Spodziewałbym się czegoś podobnego do serializowanej tablicy.

JSON.stringify(["foo", "bar"]); // -> "["foo","bar"]"
MitMaro
źródło

Odpowiedzi:

117

JSON.stringify nie działa bezpośrednio z zestawami, ponieważ dane przechowywane w zestawie nie są przechowywane jako właściwości.

Ale możesz przekonwertować zestaw na tablicę. Wtedy będziesz w stanie poprawnie go uszlachetnić.

Dowolne z poniższych załatwi sprawę:

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
źródło
2
Miałem się oświadczyć Array.from(). Ale to wygląda idiomalnie lepiej.
TaoPR
4
Żeby dodać trochę odniesienia, MDN ma kilka przykładów tej i innych powiązanych technik
Amit
5
Rozumienie listy również może zadziałać:JSON.stringify([_ for (_ of s)])
Whymarrh
1
Wszystkie świetne sposoby na zrobienie tego, niestety nie działają w Chromium 43 po wyjęciu z pudełka, ponieważ spread i Array.from nie są jeszcze zaimplementowane. Wygląda jak Babel na ratunek.
MitMaro
2
Obecna propozycja poprawy domyślnej wersji Set.prototype.toJSON: github.com/DavidBruant/Map-Set.prototype.toJSON
Oncle Tom
34

Użyj tego JSON.stringifyzamiennika:

(ponieważ toJSONjest to starszy artefakt, a lepszym podejściem jest użycie niestandardowegoreplacer , patrz 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;
}

Następnie:

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

Wynik:

"{"foo":[1,2,3],"bar":[4,5,6]}"
tanguy_k
źródło
5
w ES6 jest skrócona wersjaJSON.stringify(fooBar, (key, value) => value instanceof Set ? [...value] : value)
OzzyCzech
Odpowiedni wskrzeszacz pozostawiono jako ćwiczenie dla czytelnika? ;-)
Robert Siemer
8

Podczas gdy wszystkie powyższe działania działają, sugeruję, aby ustawić podklasę i dodać toJSONmetodę, aby upewnić się, że stringify działa poprawnie. Zwłaszcza, jeśli masz zamiar często naciągać. Używam zestawów w moich sklepach Redux i musiałem się upewnić, że to nigdy nie jest problem.

To jest podstawowa realizacja. Nazewnictwo ma na celu jedynie zilustrowanie tego, jak wybrać własny styl.

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

const set = new JSONSet([1, 2, 3])
console.log(JSON.stringify(set))
Stephen Bolton
źródło
4
Nie polecałbym tego podejścia, ponieważ toJSONjest uważane za starszą funkcję. Propozycja dodania toJSONdo obu seti mapzostała odrzucona: github.com/DavidBruant/Map-Set.prototype.toJSON/issues/16
MitMaro
Nadpisywanie constructornie jest konieczne.
Justin Johnson