Chciałbym zacząć używać ES6 Map zamiast obiektów JS, ale jestem powstrzymywany, ponieważ nie mogę dowiedzieć się, jak JSON.stringify () a Map. Moje klucze są łańcuchami, a moje wartości zawsze będą wymienione. Czy naprawdę muszę napisać metodę opakowania, aby serializować?
110
[...someMap.entries()].join(';')
; w przypadku czegoś bardziej złożonego możesz spróbować czegoś podobnego, używając czegoś takiego jak[...someMap.entries()].reduce((acc, cur) => acc + `${cur[0]}:${/* do something to stringify cur[1] */ }`, '')
obj[key]
może przynieść coś nieoczekiwanego. Rozważ sprawęif (!obj[key]) obj[key] = newList; else obj[key].mergeWith(newList);
.Odpowiedzi:
Oba
JSON.stringify
iJSON.parse
popierają drugi argument.replacer
ireviver
odpowiednio. Z zamiennikiem i odświeżaczem poniżej możliwe jest dodanie obsługi natywnego obiektu Map, w tym głęboko zagnieżdżonych wartościfunction replacer(key, value) { const originalObject = this[key]; if(originalObject instanceof Map) { return { dataType: 'Map', value: Array.from(originalObject.entries()), // or with spread: value: [...originalObject] }; } else { return value; } }
function reviver(key, value) { if(typeof value === 'object' && value !== null) { if (value.dataType === 'Map') { return new Map(value.value); } } return value; }
Zastosowanie :
const originalValue = new Map([['a', 1]]); const str = JSON.stringify(originalValue, replacer); const newValue = JSON.parse(str, reviver); console.log(originalValue, newValue);
Głębokie zagnieżdżanie dzięki połączeniu tablic, obiektów i map
const originalValue = [ new Map([['a', { b: { c: new Map([['d', 'text']]) } }]]) ]; const str = JSON.stringify(originalValue, replacer); const newValue = JSON.parse(str, reviver); console.log(originalValue, newValue);
źródło
dataType
, nie mogę wymyślić prostszego sposobu. Dzięki.Nie możesz bezpośrednio zdefiniować
Map
instancji, ponieważ nie ma ona żadnych właściwości, ale możesz przekonwertować ją na tablicę krotek:jsonText = JSON.stringify(Array.from(map.entries()));
Na odwrót użyj
map = new Map(JSON.parse(jsonText));
źródło
Map
s, dobrze współpracuje z konstruktorem i iteratorem. Jest to również jedyna rozsądna reprezentacja map, które mają klucze niebędące łańcuchami, a obiekt nie będzie tam działał.JSON.stringify(Object.fromEntries(map.entries()))
inew Map(Object.entries(JSON.parse(jsonText)))
key
jest obiektem, np."{"[object Object]":{"b":2}}"
- klucze obiektów są jedną z głównych funkcji MapNie możesz.
Kluczami mapy mogą być cokolwiek, w tym obiekty. Ale składnia JSON zezwala tylko na ciągi jako klucze. Więc w ogólnym przypadku jest to niemożliwe.
W takim przypadku możesz użyć zwykłego obiektu. Będzie miał następujące zalety:
źródło
hasOwnProperty
. Bez tego Firefox iteruje obiekty znacznie szybciej niż mapy. Mapy są jednak nadal szybsze w Chrome. jsperf.com/es6-map-vs-object-properties/95Chociaż nie ma jeszcze metody dostarczonej przez ecmascript, nadal można to zrobić za pomocą,
JSON.stingify
jeśli mapujesz naMap
prymityw JavaScript. Oto próbka,Map
której użyjemy.const map = new Map(); map.set('foo', 'bar'); map.set('baz', 'quz');
Przechodzenie do obiektu JavaScript
Możesz przekonwertować na literał obiektu JavaScript za pomocą następującej funkcji pomocniczej.
const mapToObj = m => { return Array.from(m).reduce((obj, [key, value]) => { obj[key] = value; return obj; }, {}); }; JSON.stringify(mapToObj(map)); // '{"foo":"bar","baz":"quz"}'
Przechodzenie do tablicy obiektów JavaScript
Funkcja pomocnicza dla tego byłaby jeszcze bardziej kompaktowa
const mapToAoO = m => { return Array.from(m).map( ([k,v]) => {return {[k]:v}} ); }; JSON.stringify(mapToAoO(map)); // '[{"foo":"bar"},{"baz":"quz"}]'
Przechodzenie do Array of Arrays
Jest to jeszcze łatwiejsze, możesz po prostu użyć
JSON.stringify( Array.from(map) ); // '[["foo","bar"],["baz","quz"]]'
źródło
Korzystanie z rozszerzonej mapy sytax można serializować w jednej linii:
JSON.stringify([...new Map()]);
i zdeserializuj go za pomocą:
let map = new Map(JSON.parse(map));
źródło
Stringify do
Map
instancji (przedmioty jak klucze są OK) :JSON.stringify([...map])
lub
JSON.stringify(Array.from(map))
lub
JSON.stringify(Array.from(map.entries()))
format wyjściowy:
// [["key1","value1"],["key2","value2"]]
źródło
Lepsze rozwiązanie
// somewhere... class Klass extends Map { toJSON() { var object = { }; for (let [key, value] of this) object[key] = value; return object; } } // somewhere else... import { Klass as Map } from '@core/utilities/ds/map'; // <--wherever "somewhere" is var map = new Map(); map.set('a', 1); map.set('b', { datum: true }); map.set('c', [ 1,2,3 ]); map.set( 'd', new Map([ ['e', true] ]) ); var json = JSON.stringify(map, null, '\t'); console.log('>', json);
Wynik
> { "a": 1, "b": { "datum": true }, "c": [ 1, 2, 3 ], "d": { "e": true } }
Mam nadzieję, że to mniej wstydliwe niż powyższe odpowiedzi.
źródło
IJSONAble
interfejs (oczywiście używając TypeScript).Poniższe rozwiązanie działa, nawet jeśli masz zagnieżdżone mapy
function stringifyMap(myMap) { function selfIterator(map) { return Array.from(map).reduce((acc, [key, value]) => { if (value instanceof Map) { acc[key] = selfIterator(value); } else { acc[key] = value; } return acc; }, {}) } const res = selfIterator(myMap) return JSON.stringify(res); }
źródło
Map
i (co gorsza), że każda mapa podrzędna (zawierająca) była również pierwotnie mapą. W przeciwnym razie nie ma sposobu, aby mieć pewność, żearray of pairs
nie ma być po prostu dokładnie tym, zamiast Mapą. Hierarchie obiektów i tablic nie są obciążone podczas analizowania. Każda prawidłowa serializacjaMap
wyraźnie wskazywałaby, że jest to plikMap
.Biorąc pod uwagę twój przykład jest prostym przypadkiem użycia, w którym klucze będą prostymi typami, myślę, że jest to najłatwiejszy sposób na stringifikację mapy przez JSON.
JSON.stringify(Object.fromEntries(map));
Sposób, w jaki myślę o podstawowej strukturze danych Map, to tablica par klucz-wartość (jak same tablice). Więc coś takiego:
const myMap = new Map([ ["key1", "value1"], ["key2", "value2"], ["key3", "value3"] ]);
Ponieważ ta podstawowa struktura danych jest tym, co znajdujemy w Object.entries, możemy wykorzystać natywną metodę JavaScript
Object.fromEntries()
na Mapie, tak jak w Array:Object.fromEntries(myMap); /* { key1: "value1", key2: "value2", key3: "value3" } */
A potem wszystko, co pozostaje, to użycie JSON.stringify () w wyniku tego.
źródło