JSON merangkai Set

102

Bagaimana satu JSON.stringify () menjadi Set ?

Hal-hal yang tidak berfungsi di Chromium 43:

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

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

Saya berharap untuk mendapatkan sesuatu yang mirip dengan array serial.

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

Jawaban:

108

JSON.stringify tidak langsung bekerja dengan kumpulan karena data yang disimpan dalam kumpulan tidak disimpan sebagai properti.

Tapi Anda bisa mengonversi set ke array. Kemudian Anda akan bisa merangkainya dengan benar.

Salah satu dari berikut ini akan membantu:

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
sumber
2
Saya akan melamar Array.from(). Tapi ini terlihat lebih baik secara idiom.
TaoPR
3
Hanya untuk menambahkan beberapa referensi, MDN memiliki beberapa contoh tentang ini dan teknik terkait lainnya
Amit
5
Pemahaman daftar dapat bekerja juga:JSON.stringify([_ for (_ of s)])
Whymarrh
1
Semua cara hebat untuk melakukannya, sayangnya mereka tidak berfungsi di Chromium 43 di luar kotak karena tersebar dan Array.from belum diterapkan. Sepertinya Babel akan menyelamatkan.
MitMaro
2
Proposal saat ini untuk meningkatkan default Set.prototype.toJSON: github.com/DavidBruant/Map-Set.prototype.toJSON
Oncle Tom
34

Gunakan JSON.stringifypengganti ini :

(karena toJSONmerupakan artefak lama, dan pendekatan yang lebih baik adalah menggunakan kustomreplacer , lihat 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;
}

Kemudian:

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

Hasil:

"{"foo":[1,2,3],"bar":[4,5,6]}"
tanguy_k
sumber
5
ada versi singkat di ES6JSON.stringify(fooBar, (key, value) => value instanceof Set ? [...value] : value)
OzzyCzech
Reviver yang sesuai dibiarkan sebagai latihan untuk pembaca? ;-)
Robert Siemer
7

Sementara semua pekerjaan di atas saya sarankan agar Anda mengatur subclass dan menambahkan toJSONmetode untuk memastikan bahwa itu merangkai dengan benar. Apalagi jika Anda akan sering merangkai. Saya menggunakan set di toko Redux saya dan perlu memastikan ini tidak pernah menjadi masalah.

Ini adalah implementasi dasar. Penamaan hanya untuk menggambarkan titik pilih gaya Anda sendiri.

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

const set = new JSONSet([1, 2, 3])
console.log(JSON.stringify(set))
Stephen Bolton
sumber
4
Saya tidak akan merekomendasikan pendekatan ini karena toJSONdianggap sebagai fitur lama. Proposal untuk ditambahkan toJSONke keduanya setdan mapditolak: github.com/DavidBruant/Map-Set.prototype.toJSON/issues/16
MitMaro
Mengganti constructortidak perlu.
Justin Johnson