How do you JSON.stringify an ES6 Map?

JavascriptJsonDictionaryEcmascript 6

Javascript Problem Overview


I'd like to start using ES6 Map instead of JS objects but I'm being held back because I can't figure out how to JSON.stringify() a Map. My keys are guaranteed to be strings and my values will always be listed. Do I really have to write a wrapper method to serialize?

Javascript Solutions


Solution 1 - Javascript

Both JSON.stringify and JSON.parse support a second argument. replacer and reviver respectively. With replacer and reviver below it's possible to add support for native Map object, including deeply nested values

function replacer(key, value) {
  if(value instanceof Map) {
    return {
      dataType: 'Map',
      value: Array.from(value.entries()), // or with spread: value: [...value]
    };
  } else {
    return value;
  }
}
function reviver(key, value) {
  if(typeof value === 'object' && value !== null) {
    if (value.dataType === 'Map') {
      return new Map(value.value);
    }
  }
  return value;
}

Usage:

const originalValue = new Map([['a', 1]]);
const str = JSON.stringify(originalValue, replacer);
const newValue = JSON.parse(str, reviver);
console.log(originalValue, newValue);

Deep nesting with combination of Arrays, Objects and Maps

const originalValue = [
  new Map([['a', {
    b: {
      c: new Map([['d', 'text']])
    }
  }]])
];
const str = JSON.stringify(originalValue, replacer);
const newValue = JSON.parse(str, reviver);
console.log(originalValue, newValue);

Solution 2 - Javascript

You can't directly stringify the Map instance as it doesn't have any properties, but you can convert it to an array of tuples:

jsonText = JSON.stringify(Array.from(map.entries()));

For the reverse, use

map = new Map(JSON.parse(jsonText));

Solution 3 - Javascript

You can't.

The keys of a map can be anything, including objects. But JSON syntax only allows strings as keys. So it's impossible in a general case.

> My keys are guaranteed to be strings and my values will always be lists

In this case, you can use a plain object. It will have these advantages:

  • It will be able to be stringified to JSON.
  • It will work on older browsers.
  • It might be faster.

Solution 4 - Javascript

While there is no method provided by ecmascript yet, this can still be done using JSON.stingify if you map the Map to a JavaScript primitive. Here is the sample Map we'll use.

const map = new Map();
map.set('foo', 'bar');
map.set('baz', 'quz');

Going to an JavaScript Object

You can convert to JavaScript Object literal with the following helper function.

const mapToObj = m => {
  return Array.from(m).reduce((obj, [key, value]) => {
    obj[key] = value;
    return obj;
  }, {});
};

JSON.stringify(mapToObj(map)); // '{"foo":"bar","baz":"quz"}'

Going to a JavaScript Array of Objects

The helper function for this one would be even more compact

const mapToAoO = m => {
  return Array.from(m).map( ([k,v]) => {return {[k]:v}} );
};

JSON.stringify(mapToAoO(map)); // '[{"foo":"bar"},{"baz":"quz"}]'

Going to Array of Arrays

This is even easier, you can just use

JSON.stringify( Array.from(map) ); // '[["foo","bar"],["baz","quz"]]'

Solution 5 - Javascript

Using spread sytax Map can be serialized in one line:

JSON.stringify([...new Map()]);

and deserialize it with:

let map = new Map(JSON.parse(map));

Solution 6 - Javascript

Given your example is a simple use case in which keys are going to be simple types, I think this is the easiest way to JSON stringify a Map.

JSON.stringify(Object.fromEntries(map));

The way I think about the underlying data structure of a Map is as an array of key-value pairs (as arrays themselves). So, something like this:

const myMap = new Map([     ["key1", "value1"],
     ["key2", "value2"],
     ["key3", "value3"]
]);

Because that underlying data structure is what we find in Object.entries, we can utilize the native JavaScript method of Object.fromEntries() on a Map as we would on an Array:

Object.fromEntries(myMap);

/*
{
     key1: "value1",
     key2: "value2",
     key3: "value3"
}
*/

And then all you're left with is using JSON.stringify() on the result of that.

Solution 7 - Javascript

A Better Solution

    // somewhere...
    class Klass extends Map {
        
        toJSON() {
            var object = { };
            for (let [key, value] of this) object[key] = value;
            return object;
        }
        
    }

    // somewhere else...
    import { Klass as Map } from '@core/utilities/ds/map';  // <--wherever "somewhere" is

    var map = new Map();
    map.set('a', 1);
    map.set('b', { datum: true });
    map.set('c', [ 1,2,3 ]);
    map.set( 'd', new Map([ ['e', true] ]) );

    var json = JSON.stringify(map, null, '\t');
    console.log('>', json);
Output
    > {
        "a": 1,
        "b": {
            "datum": true
        },
        "c": [
            1,
            2,
            3
        ],
        "d": {
            "e": true
        }
    }

Hope that is less cringey than the answers above.

Solution 8 - Javascript

Stringify a Map instance (objects as keys are OK):

JSON.stringify([...map])

or

JSON.stringify(Array.from(map))

or

JSON.stringify(Array.from(map.entries()))

output format:

// [["key1","value1"],["key2","value2"]]

Solution 9 - Javascript

Below solution works even if you have nested Maps

function stringifyMap(myMap) {
    function selfIterator(map) {
        return Array.from(map).reduce((acc, [key, value]) => {
            if (value instanceof Map) {
                acc[key] = selfIterator(value);
            } else {
                acc[key] = value;
            }

            return acc;
        }, {})
    }

    const res = selfIterator(myMap)
    return JSON.stringify(res);
}

Solution 10 - Javascript

The very simple way.

  const map = new Map();
  map.set('Key1', "Value1");
  map.set('Key2', "Value2");
  console.log(Object.fromEntries(map));

` Output:-

{"Key1": "Value1","Key2": "Value2"}

Solution 11 - Javascript

Just want to share my version for both Map and Set JSON.stringify only. I'm sorting them, useful for debugging...

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;
}

Usage:

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));

Result:

{
  "chars": [
    "a",
    "b"
  ],
  "numbers": [
    1,
    2,
    3
  ]
}

Solution 12 - Javascript

Although there would be some scenarios where if you were the creator of the map you would write your code in a separate 'src' file and save a copy as a .txt file and, if written concisely enough, could easily be read in, deciphered, and added to server-side.

The new file would then be saved as a .js and a reference to it sent back from the server. The file would then reconstruct itself perfectly once read back in as JS. The beauty being that no hacky iterating or parsing is required for reconstruction.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionrynopView Question on Stackoverflow
Solution 1 - JavascriptPawelView Answer on Stackoverflow
Solution 2 - JavascriptBergiView Answer on Stackoverflow
Solution 3 - JavascriptOriolView Answer on Stackoverflow
Solution 4 - JavascriptEvan CarrollView Answer on Stackoverflow
Solution 5 - JavascriptmetodribicView Answer on Stackoverflow
Solution 6 - JavascriptAlok SomaniView Answer on Stackoverflow
Solution 7 - JavascriptCodyView Answer on Stackoverflow
Solution 8 - Javascriptam0waView Answer on Stackoverflow
Solution 9 - JavascriptImamudin NaseemView Answer on Stackoverflow
Solution 10 - JavascriptRakesh Singh BalharaView Answer on Stackoverflow
Solution 11 - JavascriptMartin P.View Answer on Stackoverflow
Solution 12 - JavascriptCbaskey.itView Answer on Stackoverflow