Я хотел бы начать использовать карту ES6 вместо объектов JS, но меня сдерживают, потому что я не могу понять, как JSON.stringify( ) карта. Мои ключи гарантированно будут строками, и мои значения всегда будут списками. Должен ли я действительно писать метод обертки для сериализации?
Как вы используете JSON.stringify карту ES6?
Ответ 1
Вы не можете.
Ключами карты могут быть все, включая объекты. Но синтаксис JSON позволяет использовать только строки. Так что это невозможно в общем случае.
Мои ключи гарантированно будут строками, и мои значения всегда будут перечислены
В этом случае вы можете использовать простой объект. Он будет иметь следующие преимущества:
- Он сможет быть привязан к JSON.
- Он будет работать в старых браузерах.
- Это может быть быстрее.
Ответ 2
Вы не можете напрямую преобразовать в строку экземпляр Map
поскольку он не имеет никаких свойств, но вы можете преобразовать его в массив кортежей:
jsonText = JSON.stringify(Array.from(map.entries()));
Для обратного используйте
map = new Map(JSON.parse(jsonText));
Ответ 3
Хотя ecmascript еще не предоставил метод, это все же можно сделать с помощью JSON.stingify
если вы отобразите Map
в примитив JavaScript. Вот пример Map
мы будем использовать.
const map = new Map();
map.set('foo', 'bar');
map.set('baz', 'quz');
Переход к объекту JavaScript
Вы можете конвертировать в литерал JavaScript Object с помощью следующей вспомогательной функции.
const mapToObj = m => {
return Array.from(m).reduce((obj, [key, value]) => {
obj[key] = value;
return obj;
}, {});
};
JSON.stringify(mapToObj(map)); // '{"foo":"bar","baz":"quz"}'
Переход к массиву объектов JavaScript
Вспомогательная функция для этого была бы еще более компактной
const mapToAoO = m => {
return Array.from(m).map( ([k,v]) => {return {[k]:v}} );
};
JSON.stringify(mapToAoO(map)); // '[{"foo":"bar"},{"baz":"quz"}]'
Переход к массиву массивов
Это еще проще, вы можете просто использовать
JSON.stringify( Array.from(map) ); // '[["foo","bar"],["baz","quz"]]'
Ответ 4
И JSON.stringify
и JSON.parse
поддерживают второй аргумент. replacer
и reviver
соответственно. С помощью replacer и reviver ниже можно добавить поддержку нативного объекта Map, включая глубоко вложенные значения
function 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;
}
Использование:
const originalValue = new Map([['a', 1]]);
const str = JSON.stringify(originalValue, replacer);
const newValue = JSON.parse(str, reviver);
console.log(originalValue, newValue);
Глубокое вложение с комбинацией массивов, объектов и карт
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);
Ответ 5
Решение ниже работает, даже если у вас есть вложенные Карты
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);
}