如何使 JSON.parse() 将所有数字视为 BigInt?

mih*_*ebo 6 javascript json

我在 json 中有一些数字溢出了 Number 类型,所以我希望它是 bigint,但是如何呢?

{"foo":[[0],[64],[89],[97]],"bar":[[2323866757078990912,144636906343245838,441695983932742154,163402272522524744],[2477006750808014916,78818525534420994],[18577623609266200],[9008333127155712]]}
Run Code Online (Sandbox Code Playgroud)

Yev*_*kov 13

太长了;

您可以使用JSON.parse() reviver参数

详细解决方案

要以这种方式控制JSON.parse()行为,您可以使用JSON.parse( reviver) 的第二个参数 - 该函数预处理键值对(并且可能会将所需的值传递给BigInt())。

然而,被识别为数字的值仍然会被强制(指出这个问题的功劳归于@YohanesGultom)。

为了解决这个问题,您可以在源 JSON 字符串中引用大数字(将它们转换为字符串),以便在转换为bigint.

只要您希望bigint仅转换为某些数字,您就需要选择适当的标准(例如,检查该值是否超过Number.MAX_SAFE_INTEGERNumber.isSafeInteger()如 @PeterSeliger 所建议的)。

因此,您的问题可以通过以下方式解决:

// source JSON string

const input = `{"foo":[[0],[64],[89],[97]],"bar":[[2323866757078990912,144636906343245838,441695983932742154,163402272522524744],[2477006750808014916,78818525534420994],[18577623609266200],[9008333127155712]]}`


// function that implements desired criteria
// to separate *big numbers* from *small* ones
//
// (works for input parameter num of type number/string)

const isBigNumber = num => !Number.isSafeInteger(+num)


// function that enquotes *big numbers* matching
// desired criteria into double quotes inside
// JSON string
//
// (function checking for *big numbers* may be
// passed as a second parameter for flexibility)

const enquoteBigNumber = (jsonString, bigNumChecker) =>
    jsonString
        .replaceAll(
            /([:\s\[,]*)(\d+)([\s,\]]*)/g,
            (matchingSubstr, prefix, bigNum, suffix) =>
                bigNumChecker(bigNum)
                    ? `${prefix}"${bigNum}"${suffix}`
                    : matchingSubstr
        )


// parser that turns matching *big numbers* in
// source JSON string to bigint

const parseWithBigInt = (jsonString, bigNumChecker) =>
    JSON.parse(
        enquoteBigNumber(jsonString, bigNumChecker),
        (key, value) =>
            !isNaN(value) && bigNumChecker(value)
                ? BigInt(value)
                : value
    )

// resulting output

const output = parseWithBigInt(input, isBigNumber)


console.log("output.foo[1][0]: \n", output.foo[1][0], `(type: ${typeof output.foo[1][0]})`)
console.log("output.bar[0][0]: \n", output.bar[0][0].toString(), `(type: ${typeof output.bar[0][0]})`)
Run Code Online (Sandbox Code Playgroud)
.as-console-wrapper{min-height: 100% !important;}
Run Code Online (Sandbox Code Playgroud)

注意:您可能会发现用于匹配 JSON 值中的数字字符串的 RegExp 模式不太强大,因此请随意提出您的模式(因为我的模式是我为了演示目的而设法摘下头顶最快的)

注意:您仍然可以选择使用某些库,正如 @YohanesGultom 所建议的那样,但仅,向客户端捆绑包添加10k或向服务器端依赖项添加37k (可能是 docker 映像大小)可能不太好合理的。

  • 测试也可以基于... [`Number.isSafeInteger`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isSafeInteger) (2认同)