Published on

JavaScript 序列化行为 | JSON.stringify() | safe-stable-stringify | superjson

Authors
  • avatar
    Name
    Shelton Ma
    Twitter

JSON.stringify() 序列化问题

在 JavaScript 中,JSON.stringify() 可以正确序列化基本类型和普通对象,但不能正确处理某些特殊类型的数据, 比如 Set

正确序列化

  • 可以被序列化的:基本类型(string、number、boolean、null)、Array、Object
  • 不能被正确序列化的:undefined、function、Symbol、BigInt、Set、Map、WeakMap、WeakSet

处理办法

  1. Set 转数组

    const mySet = new Set([1, 2, 3]);
    console.log(JSON.stringify([...mySet])); // 输出: "[1,2,3]"
    
  2. Map 转对象

    const myMap = new Map([["a", 1], ["b", 2]]);
    console.log(JSON.stringify(Object.fromEntries(myMap))); // 输出: "{"a":1,"b":2}"
    
  3. BigInt 转字符串

    const obj = { value: BigInt(10) };
    console.log(JSON.stringify(obj, (_, value) => (typeof value === "bigint" ? value.toString() : value)));
    

第三方实现

1. superjson

  • 支持 Set、Map、BigInt、Date、RegExp 等特殊类型
  • 适用于 Next.jsReact Server Components
  • 格式非标准 JSON,需要 superjson.parse() 解析
import superjson from "superjson";

const data = {
  set: new Set(["a", "b"]),
  map: new Map([
    ["key", "value"],
  ]),
  bigInt: BigInt(123),
};

const serialized = superjson.stringify(data);
console.log(serialized);
console.log(superjson.parse(serialized));

2. safe-stable-stringify

  • 支持 BigInt
  • 支持 SetMap(转换为数组或对象)
  • 不会抛出循环引用错误
  • 序列化顺序稳定,适用于哈希计算
import stringify from "safe-stable-stringify";

const data = {
  set: new Set(["a", "b", "c"]),
  map: new Map([
    ["x", 1],
    ["y", 2],
  ]),
  bigInt: BigInt(1234567890123456789),
  nested: { a: 1, b: 2 },
};

console.log(stringify(data, null, 2));