解决json字符串中有大数的情况

436 阅读3分钟

使用 JSON.parse 自定义解析器处理 JSON 字符串中的大整数(BigInt)

在 JavaScript 中,JSON.parse() 是一种常见的将 JSON 字符串转换为 JavaScript 对象的方法。然而,当 JSON 数据中包含超出了 Number.MAX_SAFE_INTEGER(即 2^53 - 1)的大整数时,JavaScript 的默认行为会丢失精度。为了确保这些数字能够被正确地解析和保留,我们可以使用自定义的 JSON.parse 解析器函数。

问题背景

JavaScript 的 Number 类型只能安全地表示从 -2^53 + 12^53 - 1 的数值范围。超出这个范围的整数可能会导致精度丢失。例如:

console.log(Number.MAX_SAFE_INTEGER); // 9007199254740991

如果 JSON 数据中包含超过这个范围的数值,直接使用 JSON.parse() 将无法正确保留其原始值。

解决方案

我们可以通过提供一个自定义的 reviver 函数给 JSON.parse() 来处理大整数。该函数允许我们在解析过程中对每个键值对进行处理。

示例代码

以下是一个实现示例:

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <pre id="jsonCode"></pre>

  <script>
    function parseWithBigInt(jsonString) {
      return JSON.parse(jsonString, (key, value, ctx) => {
        if (typeof value === 'number' && value > Number.MAX_SAFE_INTEGER) {
          return ctx.source;
        }
        return value;
      });
    }

    const a = '{ "has_next": false, "hit": 1, "error_message": "none", "error_code": 0, "results": [{ "attributes": { "item_id": [13305082353411897111, 17329102371654584222, 13126716026931233333, 4865048943653390444, 348321779737944260, 1045353633982894700, 12831575591803073000, 15581673263967646000] } }] }';
    const resultA = parseWithBigInt(a);

    var preElement = document.getElementById("jsonCode");
    preElement.textContent = JSON.stringify(resultA, null, 2);
  </script>

</body>

</html>

关键点解释

  1. 自定义 Reviver 函数

    function parseWithBigInt(jsonString) {
      return JSON.parse(jsonString, (key, value, ctx) => {
        if (typeof value === 'number' && value > Number.MAX_SAFE_INTEGER) {
          return ctx.source;
        }
        return value;
      });
    }
    
    • 这个函数作为第二个参数传递给 JSON.parse()
    • 每次解析到一个键值对时,都会调用这个函数。
    • 如果检测到某个数值超过了 Number.MAX_SAFE_INTEGER,则返回 ctx.source(即原始字符串形式),以避免精度丢失。
    • 否则,正常返回解析后的值。
  2. 处理 JSON 字符串中的大整数

    • 在提供的 JSON 示例中,item_id 数组包含了多个超过 Number.MAX_SAFE_INTEGER 的数值。
    • 使用 parseWithBigInt() 函数后,这些数值会被保留为字符串形式,而不是转换为不精确的 Number 类型。
  3. 输出结果

    • 最终的结果通过 JSON.stringify(resultA, null, 2) 转换为格式化的 JSON 字符串,并显示在页面上的 <pre> 元素中。

输出结果示例

运行上述代码后,页面上会显示如下格式化的 JSON 数据:

{
  "has_next": false,
  "hit": 1,
  "error_message": "none",
  "error_code": 0,
  "results": [
    {
      "attributes": {
        "item_id": [
          "13305082353411897111",
          "17329102371654584222",
          "13126716026931233333",
          "4865048943653390444",
          "348321779737944260",
          "1045353633982894700",
          "12831575591803073000",
          "15581673263967646000"
        ]
      }
    }
  ]
}

可以看到,所有超过 Number.MAX_SAFE_INTEGER 的数值都被转换为字符串形式,从而避免了精度丢失。

总结

通过使用 JSON.parse() 的 reviver 函数,我们可以有效地处理 JSON 数据中的大整数问题。这种方法不仅简单易行,而且能够在解析过程中灵活地控制数据的转换方式,确保数据的完整性和准确性。

参考资料