我想开始使用ES6地图而不是JS对象,但我被阻止了,因为我不知道如何JSON.stringify()一个地图。我的键保证是字符串,我的值总是会被列出。我真的必须写一个包装器方法来序列化吗?
当前回答
尽管在某些情况下,如果你是地图的创建者,你会在一个单独的“src”文件中编写代码,并将副本保存为.txt文件,如果写得足够简洁,可以很容易地读取、破译并添加到服务器端。
然后,新文件将被保存为.js文件,并从服务器发回对该文件的引用。一旦作为JS读入,该文件将完美地重构自身。美妙之处在于重构时不需要笨拙的迭代或解析。
其他回答
非常简单的方法。
const map = new Map();
map.set('Key1', "Value1");
map.set('Key2', "Value2");
console.log(Object.fromEntries(map));
` 输出:
{"Key1": "Value1","Key2": "Value2"}
正确的往返序列化
复制并使用它。或者使用npm包。
const serialize = (value) => JSON.stringify(value, stringifyReplacer);
const deserialize = (text) => JSON.parse(text, parseReviver);
// License: CC0
function stringifyReplacer(key, value) {
if (typeof value === "object" && value !== null) {
if (value instanceof Map) {
return {
_meta: { type: "map" },
value: Array.from(value.entries()),
};
} else if (value instanceof Set) { // bonus feature!
return {
_meta: { type: "set" },
value: Array.from(value.values()),
};
} else if ("_meta" in value) {
// Escape "_meta" properties
return {
...value,
_meta: {
type: "escaped-meta",
value: value["_meta"],
},
};
}
}
return value;
}
function parseReviver(key, value) {
if (typeof value === "object" && value !== null) {
if ("_meta" in value) {
if (value._meta.type === "map") {
return new Map(value.value);
} else if (value._meta.type === "set") {
return new Set(value.value);
} else if (value._meta.type === "escaped-meta") {
// Un-escape the "_meta" property
return {
...value,
_meta: value._meta.value,
};
} else {
console.warn("Unexpected meta", value._meta);
}
}
}
return value;
}
为什么这很难?
它应该能够输入任何类型的数据,获得有效的JSON,并从那里正确地重建输入。
这意味着要处理
以对象为键的映射new Map([[{cat:1}, "value"]])。这意味着任何使用Object.fromEntries的答案都可能是错误的。 有嵌套映射的映射new Map([["key", new Map([["嵌套键","嵌套值"]])]])很多答案都回避了这一点,只回答了问题,而没有处理其他任何问题。 混合对象和映射{"key": new Map([["嵌套键","嵌套值"]])}。
在这些困难之上,序列化格式必须是明确的。否则就不能总是重建输入。顶部的答案有一个失败的测试用例,见下面。
因此,我写了这个改进版。它使用_meta而不是dataType来减少冲突,如果冲突确实发生,它实际上会明确地处理它。希望代码也足够简单,可以轻松扩展以处理其他容器。
然而,我的回答并没有试图处理非常糟糕的情况,比如具有对象属性的映射。
我的答案的一个测试用例,它演示了一些边缘情况
const originalValue = [
new Map([['a', {
b: {
_meta: { __meta: "cat" },
c: new Map([['d', 'text']])
}
}]]),
{ _meta: { type: "map" }}
];
console.log(originalValue);
let text = JSON.stringify(originalValue, stringifyReplacer);
console.log(text);
console.log(JSON.parse(text, parseReviver));
已接受答案,不往返
公认的答案真的很可爱。但是,当一个带有dataType属性的对象被传递给它时,它不会进行往返。
// Test case for the accepted answer
const originalValue = { dataType: "Map" };
const str = JSON.stringify(originalValue, replacer);
const newValue = JSON.parse(str, reviver);
console.log(originalValue, str, newValue);
// > Object { dataType: "Map" } , Map(0)
// Notice how the input was changed into something different
使用spread sytax Map可以在一行中序列化:
JSON.stringify([...new Map()]);
并反序列化它:
let map = new Map(JSON.parse(map));
虽然ecmascript还没有提供方法,但这仍然可以使用JSON来完成。如果将map映射到JavaScript原语,则使用stingify。下面是我们将使用的Map示例。
const map = new Map();
map.set('foo', 'bar');
map.set('baz', 'quz');
转到JavaScript对象
你可以用下面的辅助函数转换成JavaScript对象文字。
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"]]'
只是想分享我的Map和Set JSON版本。stringify。 我正在对它们进行排序,对调试有用……
function replacer(key, value) {
if (value instanceof Map) {
const reducer = (obj, mapKey) => {
obj[mapKey] = value.get(mapKey);
return obj;
};
return [...value.keys()].sort().reduce(reducer, {});
} else if (value instanceof Set) {
return [...value].sort();
}
return value;
}
用法:
const map = new Map();
const numbers= new Set()
numbers.add(3);
numbers.add(2);
numbers.add(3);
numbers.add(1);
const chars= new Set()
chars.add('b')
chars.add('a')
chars.add('a')
map.set("numbers",numbers)
map.set("chars",chars)
console.log(JSON.stringify(map, replacer, 2));
结果:
{
"chars": [
"a",
"b"
],
"numbers": [
1,
2,
3
]
}
推荐文章
- 如何以及为什么'a'['toUpperCase']()在JavaScript工作?
- 有Grunt生成index.html不同的设置
- 文档之间的区别。addEventListener和window。addEventListener?
- 如何检查动态附加的事件监听器是否存在?
- 如何写setTimeout与参数Coffeescript
- 将JavaScript字符串中的多个空格替换为单个空格
- JavaScript: override alert()
- 重置setTimeout
- 如何确保<select>表单字段被禁用时提交?
- jQuery有不聚焦的方法吗?
- 在STL地图中,使用map::insert比[]更好吗?
- 反应钩子-正确的方式清除超时和间隔
- 在VS Code中禁用“Comments are not allowed In JSON”错误
- TypeScript枚举对象数组
- 如何在Kotlin解析JSON ?