javascript - 如何将包含 ES5 集合和映射的对象字符串化?

标签 javascript json html

我正在开发一个 Angular 应用程序。我使用 Typescript 并且有一个包含内置 Set 和 Map 类型的特定类。我的问题是我想将我的类的实例作为 JSON 存储在浏览器的 localStorage 中,但是当我尝试将它们字符串化时,我得到这些类型的空字符串。

来自 chrom 控制台的示例:

> inst = new Object({
    'elem': new Set(),
    'str': 'somestring'
})
: Object {elem: Set(0), str: "somestring"}elem: Set(0)str: "somestring"}
> inst.elem.add('123');
: Set(1) {"123"}
> inst.elem.add('123');
: Set(1) {"123"}size: (...)__proto__: Set[[Entries]]: Array(1)0: "123"length: 1
> JSON.stringify(inst)
: "{"elem":{},"str":"somestring"}"

我唯一能想到的就是在字符串化之前将 Sets 和 Maps 分别递归地转换为 Arrays 和 Objects。但这听起来很费力。

还有更好的办法吗?谢谢。

最佳答案

将 Map 转换为简单的 Object 是行不通的,除非键恰好都是字符串。请记住,Map 可以将任何内容作为键,包括通过引用不相等但在强制转换时会产生相同字符串的内容。

序列化 Maps 和 Sets 的明显方法确实是将它们转换为数组,然后序列化它。幸运的是,您不必自己编写太多代码,只需使用内置的迭代器即可:

const map = new Map([['a', 1], ['b', 2]])
const set = new Set([2,3,5,7,11])

serializedMap = JSON.stringify([...map]) // => [["a", 1], ["b", 2]]
serializedSet = JSON.stringify([...set]) // => [2,3,5,7,11]

现在,正如您所注意到的,嵌套的映射和集合会遇到一些麻烦。为避免编写特定代码来深入研究对象并将其深层嵌套的 Map 和 Set 值转换为数组,您可以在 Map 和 Set 原型(prototype)上定义 toJSON 方法。方法是called implicitly by JSON.stringify :

Map.prototype.toJSON = function () {
    return [...this]
}
// or, if you really want to use objects:
Map.prototype.toJSON = function () {
    var obj = {}
    for(let [key, value] of this)
        obj[key] = value
    return obj
}

// and for Sets:
Set.prototype.toJSON = function () {
    return [...this]
}

请注意,toJSON 可能会在将来的某个时候为 Sets 和 Maps 定义,其行为与此不同。虽然it seems unlikely .

现在,每当您调用 JSON.stringify 并且它看到 Map 或 Set 时,它都会注意到 toJSON 方法并使用它,而不是仅仅复制对象的属性。

另一个类似且更受 ECMA 认可的解决方案是使用 JSON.stringify 的第二个参数。定义一个将预处理值的辅助函数,用适当的数组或对象替换映射和集合:

function mapReplacer(key, value) {
    if(value instanceof Map || value instanceof Set) {
        return [...value]
        // of course you can separate cases to turn Maps into objects
    }
    return value
}

现在只需将 mapReplacer 传递给 JSON.stringify:

JSON.stringify(map, mapReplacer)

关于javascript - 如何将包含 ES5 集合和映射的对象字符串化?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43704904/

相关文章:

html - 裁剪边界半径非常大的图像

json - Azure ARM 模板可变条件

javascript - Angularjs 中的 ElasticSearch 到 NVD3

javascript - 为什么 eslint 考虑 JSX 或一些 react @types undefined,因为将 typescript-eslint/parser 升级到版本 4.0.0

javascript - 如何使用 phonegap 在 iPhone 中创建联系人

.net - 配置 IIS 7.5 以发送压缩后的 JSON 响应,NO_MATCHING_CONTENT_TYPE

android - 如何将嵌套哈希表序列化/反序列化为 JSON?

html - 为什么 Ace 编辑器不将 CSS 类应用于 div?

html - 具有滚动条的相同高度 flex 元素 - flexbox

javascript - 循环中的多个 AJAX 调用