使用 JSON.parse 自定义解析器处理 JSON 字符串中的大整数(BigInt)
在 JavaScript 中,JSON.parse() 是一种常见的将 JSON 字符串转换为 JavaScript 对象的方法。然而,当 JSON 数据中包含超出了 Number.MAX_SAFE_INTEGER(即 2^53 - 1)的大整数时,JavaScript 的默认行为会丢失精度。为了确保这些数字能够被正确地解析和保留,我们可以使用自定义的 JSON.parse 解析器函数。
问题背景
JavaScript 的 Number 类型只能安全地表示从 -2^53 + 1 到 2^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>
关键点解释
-
自定义 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(即原始字符串形式),以避免精度丢失。 - 否则,正常返回解析后的值。
- 这个函数作为第二个参数传递给
-
处理 JSON 字符串中的大整数:
- 在提供的 JSON 示例中,
item_id数组包含了多个超过Number.MAX_SAFE_INTEGER的数值。 - 使用
parseWithBigInt()函数后,这些数值会被保留为字符串形式,而不是转换为不精确的Number类型。
- 在提供的 JSON 示例中,
-
输出结果:
- 最终的结果通过
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 数据中的大整数问题。这种方法不仅简单易行,而且能够在解析过程中灵活地控制数据的转换方式,确保数据的完整性和准确性。