どのようにしてES6マップをJSON.stringifyしますか?


102

JSオブジェクトの代わりにES6マップの使用を開始したいのですが、マップをJSON.stringify()する方法がわからないため、保留されています。私のキーは文字列であることが保証されており、私の値は常にリストされます。シリアル化するために本当にラッパーメソッドを記述する必要がありますか?


1
トピックに関する興味深い記事2ality.com/2015/08/es6-map-json.html
David Chase

これを機能させることができました。結果はembed.plnkr.co/oNlQQBDyJUiIQlgWUPVPのPlunkrにあります。ソリューションでは、JSON.stringify(obj、replacerFunction)を使用して、Mapオブジェクトが渡されているかどうかを確認し、MapオブジェクトをJavascriptオブジェクトに変換し(そのJSON.stringify)、文字列に変換します。
PatS 2018

1
キーが文字列(または数値)と値の配列であることが保証されている場合は、次のようなことができます[...someMap.entries()].join(';')。より複雑なものについては、次のようなものを使用して同様のことを試すことができます[...someMap.entries()].reduce((acc, cur) => acc + `${cur[0]}:${/* do something to stringify cur[1] */ }`, '')
user56reinstatemonica8

@Oriolキー名がデフォルトのプロパティと同じになる可能性がある場合はどうなりますか?obj[key]予期しない結果になる可能性があります。ケースを考えてみましょうif (!obj[key]) obj[key] = newList; else obj[key].mergeWith(newList);
フランクリンユー

回答:


65

できません。

マップのキーは、オブジェクトを含め、何でもかまいません。ただし、JSON構文では文字列のみをキーとして使用できます。したがって、一般的なケースでは不可能です。

私のキーは文字列であることが保証され、私の値は常にリストになります

この場合、プレーンオブジェクトを使用できます。次のような利点があります。

  • JSONに文字列化できるようになります。
  • それは古いブラウザで動作します。
  • それはより速いかもしれません。

30
好奇心旺盛な最新のクロムについては、どのマップも「{}」にシリアル化されます
Capaj

ここでは、「できない」と言ったときの意味を説明しました。
Oriol

7
「もっと速いかもしれない」-その上にソースはありますか?単純なハッシュマップは完全なオブジェクトよりも高速でなければならないことを想像していますが、証明はありません。:)
リレマン2016

1
@Xplouderそのテストは高価hasOwnPropertyです。それがなければ、Firefoxはマップよりもはるかに高速にオブジェクトを繰り返し処理します。ただし、Chromeではマップの方が高速です。jsperf.com/es6-map-vs-object-properties/95
Oriol

1
確かに、Firefox 45vはChrome + 49vよりも速くオブジェクトを反復処理するようです。ただし、マップはChromeのオブジェクトと比較して勝っています。
Xplouder 2016年

68

Mapプロパティがないため、インスタンスを直接文字列化することはできませんが、タプルの配列に変換できます。

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

逆の場合は、

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

6
これはJSONオブジェクトに変換されませんが、代わりに配列の配列に変換されます。同じではありません。より完全な回答については、以下のEvan Carrollの回答を参照してください。
土曜日ティル

3
@SatThiruタプルの配列はMapsの慣習的な表現であり、コンストラクターおよびイテレーターとうまく連動します。また、これは文字列以外のキーを持つマップの唯一の賢明な表現であり、オブジェクトはそこで機能しません。
ベルギ

Bergi、OPは「私のキーは文字列であることが保証されている」と言っていることに注意してください。
土曜日ティル


@Bergi Stringify keyは、オブジェクトがオブジェクトである場合は機能しません。例"{"[object Object]":{"b":2}}"-オブジェクトキーはマップの主な機能の1つです
Drenai

58

両方とも2番目の引数JSON.stringifyJSON.parseサポートします。replacerreviverそれぞれ。以下のreplacerおよびreviverを使用すると、深くネストされた値を含むネイティブMapオブジェクトのサポートを追加できます

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

使い方

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

配列、オブジェクト、マップの組み合わせによる深い入れ子

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

8
これは、これまでのところ最高の応答です
Manuel Vera Silvestre

1
ここで間違いなく最良の答えです。
JavaRunner

15

ecmascriptによって提供されるメソッドはまだありませんが、JavaScriptプリミティブにJSON.stingifyマップする場合は、これを使用して実行できますMapMapこれが使用するサンプルです。

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

JavaScriptオブジェクトに移動する

次のヘルパー関数を使用して、JavaScriptオブジェクトリテラルに変換できます。

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

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

オブジェクトのJavaScript配列に移動する

このヘルパー関数はさらにコンパクトになります

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

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

配列の配列に行く

これはさらに簡単です、あなたはただ使うことができます

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

13

スプレッド構文マップを使用すると、1行でシリアル化できます。

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

そしてそれをデシリアライズします:

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

これは1次元マップでは機能しますが、n次元マップでは機能しません。
mattsven

6

Mapインスタンスを文字列化します(キーとしてのオブジェクトは問題ありません)

JSON.stringify([...map])

または

JSON.stringify(Array.from(map))

または

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

出力フォーマット:

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

4

より良いソリューション

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

出力

    > {
        "a": 1,
        "b": {
            "datum": true
        },
        "c": [
            1,
            2,
            3
        ],
        "d": {
            "e": true
        }
    }

上記の答えよりも不快感が少ないことを願っています。


コアマップクラスを拡張してjsonにシリアル化するだけで多くの人が満足できるかどうかは
わかりませ

1
彼らはそうである必要はありませんが、それはそれを行うためのより確かな方法です。具体的には、これはSOLIDのLSPおよびOCPの原則と一致しています。つまり、ネイティブマップは拡張中であり、変更されていません。ネイティブマップでLiskov Substitution(LSP)を引き続き使用できます。確かに、それは多くの初心者や頑固な関数型プログラミングの人々が好むよりもOOPですが、少なくとも、基本的なソフトウェア設計原則の実証済みの真のベースラインに悩まされています。SOLIDのインターフェース分離原理(ISP)を実装したい場合は、小さいIJSONAbleインターフェース(もちろんTypeScriptを使用)を使用できます。
コーディ

3

マップをネストしている場合でも、以下の解決策は機能します

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

あなたの答えをテストすることなく、ネストされたマップの問題にどのように注意を向けるかをすでに感謝しています。これをJSONに正常に変換したとしても、今後行われる解析では、JSONが元々あったこと、Mapさらに(さらに悪いことに)各サブマップ(含まれている)も元々はマップであったことを明示的に認識している必要があります。それ以外の場合array of pairsは、Mapの代わりに、それがまさにそれを意図したものではないことを確認する方法はありません。オブジェクトと配列の階層は、解析時にこの負担を負いません。の適切なシリアル化Mapは、それがであることを明示的に示しますMap
ロニーベスト

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.