如何在本地存储(或其他地方)中保留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))