我想开始使用ES6地图而不是JS对象,但我被阻止了,因为我不知道如何JSON.stringify()一个地图。我的键保证是字符串,我的值总是会被列出。我真的必须写一个包装器方法来序列化吗?


当前回答

尽管在某些情况下,如果你是地图的创建者,你会在一个单独的“src”文件中编写代码,并将副本保存为.txt文件,如果写得足够简洁,可以很容易地读取、破译并添加到服务器端。

然后,新文件将被保存为.js文件,并从服务器发回对该文件的引用。一旦作为JS读入,该文件将完美地重构自身。美妙之处在于重构时不需要笨拙的迭代或解析。

其他回答

非常简单的方法。

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

` 输出:

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

正确的往返序列化

复制并使用它。或者使用npm包。

const serialize = (value) => JSON.stringify(value, stringifyReplacer);
const deserialize = (text) => JSON.parse(text, parseReviver);

// License: CC0
function stringifyReplacer(key, value) {
  if (typeof value === "object" && value !== null) {
    if (value instanceof Map) {
      return {
        _meta: { type: "map" },
        value: Array.from(value.entries()),
      };
    } else if (value instanceof Set) { // bonus feature!
      return {
        _meta: { type: "set" },
        value: Array.from(value.values()),
      };
    } else if ("_meta" in value) {
      // Escape "_meta" properties
      return {
        ...value,
        _meta: {
          type: "escaped-meta",
          value: value["_meta"],
        },
      };
    }
  }
  return value;
}

function parseReviver(key, value) {
  if (typeof value === "object" && value !== null) {
    if ("_meta" in value) {
      if (value._meta.type === "map") {
        return new Map(value.value);
      } else if (value._meta.type === "set") {
        return new Set(value.value);
      } else if (value._meta.type === "escaped-meta") {
        // Un-escape the "_meta" property
        return {
          ...value,
          _meta: value._meta.value,
        };
      } else {
        console.warn("Unexpected meta", value._meta);
      }
    }
  }
  return value;
}

为什么这很难?

它应该能够输入任何类型的数据,获得有效的JSON,并从那里正确地重建输入。

这意味着要处理

以对象为键的映射new Map([[{cat:1}, "value"]])。这意味着任何使用Object.fromEntries的答案都可能是错误的。 有嵌套映射的映射new Map([["key", new Map([["嵌套键","嵌套值"]])]])很多答案都回避了这一点,只回答了问题,而没有处理其他任何问题。 混合对象和映射{"key": new Map([["嵌套键","嵌套值"]])}。

在这些困难之上,序列化格式必须是明确的。否则就不能总是重建输入。顶部的答案有一个失败的测试用例,见下面。

因此,我写了这个改进版。它使用_meta而不是dataType来减少冲突,如果冲突确实发生,它实际上会明确地处理它。希望代码也足够简单,可以轻松扩展以处理其他容器。

然而,我的回答并没有试图处理非常糟糕的情况,比如具有对象属性的映射。

我的答案的一个测试用例,它演示了一些边缘情况

const originalValue = [
  new Map([['a', {
    b: {
      _meta: { __meta: "cat" },
      c: new Map([['d', 'text']])
    }
  }]]),
 { _meta: { type: "map" }}
];

console.log(originalValue);
let text = JSON.stringify(originalValue, stringifyReplacer);
console.log(text);
console.log(JSON.parse(text, parseReviver));

已接受答案,不往返

公认的答案真的很可爱。但是,当一个带有dataType属性的对象被传递给它时,它不会进行往返。

// Test case for the accepted answer
const originalValue = { dataType: "Map" };
const str = JSON.stringify(originalValue, replacer);
const newValue = JSON.parse(str, reviver);
console.log(originalValue, str, newValue); 
// > Object { dataType: "Map" } , Map(0)
// Notice how the input was changed into something different

使用spread sytax Map可以在一行中序列化:

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

并反序列化它:

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

虽然ecmascript还没有提供方法,但这仍然可以使用JSON来完成。如果将map映射到JavaScript原语,则使用stingify。下面是我们将使用的Map示例。

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"]]'

只是想分享我的Map和Set JSON版本。stringify。 我正在对它们进行排序,对调试有用……

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

用法:

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

结果:

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