web-dev-qa-db-fra.com

Comment JSON.stringify une carte ES6?

Je voudrais commencer à utiliser ES6 Map à la place des objets JS, mais je suis retenu car je ne sais pas comment JSON.stringify () une Map. Mes clés sont garanties être des chaînes et mes valeurs seront toujours des listes. Dois-je vraiment écrire une méthode de wrapper pour sérialiser?

66
rynop

Tu ne peux pas.

Les clés d'une carte peuvent être n'importe quoi, y compris des objets. Mais la syntaxe JSON autorise uniquement les chaînes en tant que clés. Donc, c'est impossible dans un cas général.

Mes clés sont garanties être des chaînes et mes valeurs seront toujours des listes

Dans ce cas, vous pouvez utiliser un objet simple. Il aura ces avantages:

  • Il pourra être codé en JSON.
  • Cela fonctionnera sur les anciens navigateurs.
  • Cela pourrait être plus rapide.
45
Oriol

Vous ne pouvez pas directement hiérarchiser l'instance Map car elle n'a aucune propriété, mais vous pouvez la convertir en un tableau de n-uplets:

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

Pour l'inverse, utilisez

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

Tous les deux JSON.stringify et JSON.parse supporte un deuxième argument. replacer et reviver respectivement. Avec replacer et reviver ci-dessous, il est possible d'ajouter le support pour les objets Map natifs, y compris les valeurs profondément imbriquées.

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

sage:

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

Nidification en profondeur avec combinaison de tableaux, d'objets et de cartes

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

Bien que ecmascript n’ait pas encore fourni de méthode, ceci peut toujours être fait en utilisant JSON.stingify si vous mappez le Map à une primitive JavaScript. Voici l'exemple Map que nous allons utiliser.

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

Aller à un objet JavaScript

Vous pouvez convertir en littéral objet JavaScript avec la fonction d'assistance suivante.

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

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

Aller à un tableau d'objets JavaScript

La fonction d'assistance pour celui-ci serait encore plus compacte

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

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

Aller à tableau de tableaux

C'est encore plus facile, vous pouvez simplement utiliser

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

La solution ci-dessous fonctionne même si vous avez des cartes imbriquées

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);
}
0
Imamudin Naseem