Converting ES6 Maps to and from JSON

[2015-08-17] esnext, dev, javascript
(Ad, please don’t block)

When you have key-value data whose keys you don’t know in advance, it’s generally better to store it in an ES6 Map than in an object. But how do you convert Maps to and from JSON? This blog post tells you.

Background knowledge:

Arbitrary Maps as JSON via Arrays of pairs  

If a Map contains arbitrary (JSON-compatible) data, we can convert it to JSON by encoding it as an Array of key-value pairs (2-element Arrays).

Converting a Map to and from an Array of pairs  

The spread operator lets you convert a Map to an Array of pairs:

> let myMap = new Map().set(true, 7).set({foo: 3}, ['abc']);
> [...myMap]
[ [ true, 7 ], [ { foo: 3 }, [ 'abc' ] ] ]

The Map constructor lets you convert an Array of pairs to a Map:

> new Map([[true, 7], [{foo: 3}, ['abc']]])
Map {true => 7, Object {foo: 3} => ['abc']}

The conversion to and from JSON  

Let’s use this knowledge to convert any Map with JSON-compatible data to JSON and back:

function mapToJson(map) {
  return JSON.stringify([...map]);
}
function jsonToMap(jsonStr) {
  return new Map(JSON.parse(jsonStr));
}

The following interaction demonstrates how these functions are used:

> let myMap = new Map().set(true, 7).set({foo: 3}, ['abc']);
> mapToJson(myMap)
'[[true,7],[{"foo":3},["abc"]]]'
> jsonToMap('[[true,7],[{"foo":3},["abc"]]]')
Map {true => 7, Object {foo: 3} => ['abc']}

String Maps as JSON via objects  

Whenever a Map only has strings as keys, you can convert it to JSON by encoding it as an object.

Converting a string Map to and from an object  

The following two function convert string Maps to and from objects:

function strMapToObj(strMap) {
  let obj = Object.create(null);
  for (let [k,v] of strMap) {
    // We don’t escape the key '__proto__'
    // which can cause problems on older engines
    obj[k] = v;
  }
  return obj;
}
function objToStrMap(obj) {
  let strMap = new Map();
  for (let k of Object.keys(obj)) {
    strMap.set(k, obj[k]);
  }
  return strMap;
}

Let’s use these two functions:

> let myMap = new Map().set('yes', true).set('no', false);
> strMapToObj(myMap)
{ yes: true, no: false }
> objToStrMap({yes: true, no: false})
[ [ 'yes', true ], [ 'no', false ] ]

The conversion to and from JSON  

With these helper functions, the conversion to JSON works as follows:

function strMapToJson(strMap) {
  return JSON.stringify(strMapToObj(strMap));
}
function jsonToStrMap(jsonStr) {
  return objToStrMap(JSON.parse(jsonStr));
}

This is an example of using these functions:

> let myMap = new Map().set('yes', true).set('no', false);
> strMapToJson(myMap)
'{"yes":true,"no":false}'
> jsonToStrMap('{"yes":true,"no":false}');
Map {'yes' => true, 'no' => false}