Serialize Map object with jQuery/JS

[This is first question on SO, so apologize me for any mistake]

I'm trying to save a Map, like the one below, in a cookie.

var myMap = new Map();
myMap.set("k1", {
    a1: "...",
    a2: "...",
    a3: "..."
});

For this, I have to format as JSON. I tried many methods, like:

$.toJSON(myMap)
$.param(myMap)
JSON.stringify(myMap)

But none of them seems to work...

So, I did this:

var serial = [];
myMap.forEach(function(value){
    serial.push(value);
});
var result = $.toJSON(serial)

(Having to reconstruct the key on decoding the JSON...)

There is a better way to serialize a Map object?

Answers:

Answer

Not exactly a typical "stringify", but you can use the spread operator combined with JSON.stringify(), that will give you an array...

var myMap = new Map();
myMap.set("k1", { a1: "...", a2: "...", a3: "..." });
myMap.set("k2", { b1: "...", b2: "...", b3: "..." });

var myJSON = JSON.stringify([...myMap]);
alert(myJSON);

This will give you...

[["k1",{"a1":"...","a2":"...","a3":"..."}],["k2",{"b1":"...","b2":"...","b3":"..."}]]

And to convert it to Map again...

var recoveredMap = new Map(JSON.parse(myJSON));
Answer

While spread operator is good if you want to stringify immediate maps, you'll face problems if they are nested within any data structures.

Both JSON.stringify and JSON.parse support callback functions:

JSON.stringify(value[, replacer[, space]])
JSON.parse(text[, reviver])

So you can write functions such as:

function replacer (key, value){
    if (value.__proto__ == Map.prototype) {
        return {
            _type: "map",
            map: [...value],
        }
    } else return value;
}

function reviver (key, value){
    if (value._type == "map") return new Map(value.map);
    else return value;
}

Now you can easily stringify/parse maps no matter how deep they are nested:

let obj = {
    map: new Map([
        [1, new Map([
            [1,2],
            [3,4],
        ])],
        [2,3],
    ]),
};
console.log(obj);
let str = JSON.stringify(obj, replacer);
console.log(str);
console.log(JSON.parse(str));
console.log(JSON.parse(str, reviver));
Answer

What about using Array.from to convert your Map into an array

// initialize the map
var myMap = new Map();
myMap.set("k1", {
  a1: "...",
  a2: "...",
  a3: "..."
});
myMap.set("k2", {
  a1: "...",
  a2: "...",
  a3: "..."
});


// serialize the map by converting it to an array
var mapAsArray = Array.from(myMap);
console.log('Map as array ',mapAsArray);

var serializedMap = JSON.stringify(mapAsArray);
console.log(serializedMap)

// deserialize into a new map
var map = new Map(JSON.parse(serializedMap))
console.log(map.size)

Answer

There's a new JS feature - Object.fromEntries. It can parse a map into an object

const obj = {a: 1, b: 2}
const map = new Map(Object.entries(obj))
const objectCopy = Object.fromEntries(map)

Compatibility is ok (Chrome, FF, Safari) and a polyfill exists. We can also expect compatibility to spread to all browsers since fromEntries is a "stage 4" proposal (approved).
See Compatibility here

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.