2015-08-17

Converting ES6 Maps to and from JSON

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:

  • More information on ES6 Maps: chapter “Maps and Sets” in “Exploring ES6”.
  • More information on JSON: chapter “JSON” in “Speaking JavaScript”.

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}

No comments: