如何在本地存储(或其他地方)中保留ES6映射?
var a = new Map([[ 'a', 1 ]]); a.get('a') // 1 var forStorageSomewhere = JSON.stringify(a); // Store, in my case, in localStorage. // Later: var a = JSON.parse(forStorageSomewhere); a.get('a') // TypeError: undefined is not a function
不幸的是JSON.stringify(a);
只是返回“{}”,这意味着恢复时变成空对象。
我发现es6-mapify允许在一个Map和一个普通对象之间进行向上/向下的转换,所以这可能是一个解决scheme,但是我希望我需要求助于一个外部的依赖关系来保存我的地图。
假设您的密钥和您的值都是可串行化的,
localStorage.myMap = JSON.stringify(Array.from(map.entries()));
应该pipe用。 相反,使用
map = new Map(JSON.parse(localStorage.myMap));
通常,序列化只有在这个属性成立时才有用
deserialize(serialize(data)).get(key) ≈ data.get(key)
其中a ≈ b
可以定义为serialize(a) === serialize(b)
。
序列化对象到JSON时,这是满足的:
var obj1 = {foo: [1,2]}, obj2 = JSON.parse(JSON.stringify(obj1)); obj1.foo; // [1,2] obj2.foo; // [1,2] :) JSON.stringify(obj1.foo) === JSON.stringify(obj2.foo); // true :)
这是可行的,因为属性只能是string,可以无损地串行化为string。
但是,ES6映射允许任意值作为键。 这是有问题的,因为对象是唯一标识的,而不是它们的数据。 而当序列化对象,你失去了参考。
var key = {}, map1 = new Map([ [1,2], [key,3] ]), map2 = new Map(JSON.parse(JSON.stringify([...map1.entries()]))); map1.get(1); // 2 map2.get(1); // 2 :) map1.get(key); // 3 map2.get(key); // undefined :(
所以我想说一般情况下是不可能的 。
而对于那些可以工作的情况,很可能你可以使用普通对象而不是地图 。 这也会有这些好处:
- 它将能够被string化为JSON而不会丢失关键信息。
- 它将在较旧的浏览器上工作。
- 这可能会更快。
根据Oriol的 回答 ,我们可以做得更好一点。 只要存在原始根或入口地图,我们仍然可以使用键的对象引用,并且每个对象键都可以从该根键传递而来。
修改Oriol的例子使用道格拉斯Crockford的JSON.decycle和JSON.retrocycle我们可以创build一个映射来处理这种情况:
var key = {}, map1 = new Map([ [1, key], [key, 3] ]), map2 = new Map(JSON.parse(JSON.stringify([...map1.entries()]))), map3 = new Map(JSON.retrocycle(JSON.parse(JSON.stringify(JSON.decycle([...map1.entries()]))))); map1.get(1); // key map2.get(1); // key map3.get(1); // key map1.get(map1.get(1)); // 3 :) map2.get(map2.get(1)); // undefined :( map3.get(map3.get(1)); // 3 :)
循环和反循环使得用JSON编码循环结构和标记成为可能。 如果我们想在对象之间build立关系而不在这些对象本身上创build附加属性,或者想要通过使用ES6映射将对象与基本对象相互关联,反之亦然,这是非常有用的。
一个陷阱就是我们不能使用原来的关键对象作为新的地图( map3.get(key);
会返回undefined)。 但是,保留原始的键引用,但是新分析的JSON映射似乎是一个不太可能的情况。
当您有多维地图时,接受的答案将失败。 我们应该时刻牢记,一个Map对象可以将另一个Map对象作为一个键或值。
所以处理这个工作的一个更好更安全的方法可能如下:
function arrayifyMap(m){ return m.constructor === Map ? [...m].map(([v,k]) => [arrayifyMap(v),arrayifyMap(k)]) : m; }
一旦你有这个工具,那么你总是可以这样做;
localStorage.myMap = JSON.stringify(arrayifyMap(myMap))