如何在JavaScript中将BigInt转换为Number?

122
我发现自己处于这样一种情况,我想将一个 BigInt 值转换为 Number 值。既然我知道我的值是一个安全整数,那么我该如何进行转换呢?

4
你是在指“第三阶段提案”吗?相关内容可以在这里找到:https://github.com/tc39/proposal-bigint#interoperation-with-number-and-string。 - Sebastian Simon
很好 @Xufox,感谢您的编辑。 - Lucio Paiva
4个回答

177

原来将它传递给Number构造函数就像轻而易举的事情一样:

const myBigInt = BigInt(10);  // `10n` also works
const myNumber = Number(myBigInt);
当然,需要记住您的 BigInt 值必须在 [Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER] 范围内,这样转换才能正常工作,正如问题所述。

5
我想知道为什么还不支持 +myBigInt - Mohammad
5
@Mohammad 点击链接查看:https://github.com/tc39/proposal-bigint/blob/master/ADVANCED.md#dont-break-asmjs - Kartik Soneji

29
你可以使用parseIntNumber

const large =  BigInt(309);
const b = parseInt(large);
console.log(b);
const n = Number(large);
console.log(n);


8
出于性能方面的考虑,我建议不要使用parseInt。是的,根据规范,parseIntNumber都应该将BigInt转换为字符串,然后再转换为数字进行转换。然而,与Number的语义相比,尤其是在BigInt(number)生成一个BigInt时,parseInt的语义更加复杂,这使得浏览器厂商更有可能对Number(bigValue)进行更多优化,而跳过内部的字符串处理过程。因此,建议使用Number而不是parseInt来提高性能。 - Jack G
@JackGiffin请查看此链接:https://dev59.com/Qm855IYBdhLWcg3w5IrZ。在某些情况下,`parseInt`可能更好。 - I_Al-thamary
1
很抱歉,我不太明白。我同意parseIntNumber有不同的行为,但是,为了将BigInt转换为数字,我想不出它们会有任何不同的情况。也许您可以提供一个例子,说明NumberparseInt在将BigInt转换为数字时有所不同,以便启发我。非常感谢。 - Jack G
@JackGiffin 在 BigInts 这种情况下你是完全正确的,而我需要展示的是 parseIntNumber 有着不同的行为,具体在上面的链接中可以看到例子。 - I_Al-thamary
2
@I_Al-thamary:在使用parseInt时,最佳实践是使用基数。 - naveen
如果BigInt值太大而无法表示为数字,则转换将导致精度损失,甚至可能返回NaN,并且parseInt会导致TypeError。 const tooBigIntValue = BigInt(Number.MAX_SAFE_INTEGER) + BigInt(1); const convertedValue = Number(tooBigIntValue); console.log(tooBigIntValue); // 9007199254740993n console.log(convertedValue); // NaN const convertedValue_parseInt = parseInt(tooBigIntValue)+ BigInt(1); console.log(convertedValue_parseInt); // TypeError - I_Al-thamary

1

8
@zr0gravity7 @naveen,我有机会测试了一下,这些方法并不返回数字,而是返回 BigInt 值。它们的名称是误导性的,因为 N 暗示着 Number,但实际上它们仍然返回 BigInt 值。尝试运行 typeof BigInt.asIntN(64, 1n),你会发现它报告的是 bigint。所以这个答案实际上并没有回答问题。 - Lucio Paiva
1
确实如此。一个令人困惑的名称。正在阅读文档。<3 - naveen
6
这个名字的解释是,“intN”是“int32”、“int64”、“int555”等的概括;或者换句话说,“intN”是“N位整数”的缩写。这个N的值是函数的第一个参数。替代规范可以提供BigInt.asInt64(x)BigInt.asInt32(x),但为了最大限度的灵活性,决定只提供单个BigInt.asIntN(N,x) - jmrk
3
as(Ui|I)ntN并不像你所说的那样,也不回答OP的问题。这些函数接受一个BigInt并返回模2^N的BigInt。 - Chris_F

1
避免陷阱
我知道原始问题的范围是在你已经有一个“安全整数”的情况下,但我想给其他人提供一些范围,告诉他们应该如何处理它。

Number.isSafeInteger

人们可能会认为你可以利用Number.isSafeInteger,但是像下面这个简单的片段所示,即使BigInt的值在Number的最小和最大边界之内,利用该函数始终会返回false

console.log(Number.isSafeInteger(BigInt(1)))
// Returns false

使用结果的实现

这个实现利用了TS-Results库来返回成功或错误的响应,而不是像抛出异常那样处理。

如果你不想使用Results库,你可以选择返回值并在其他情况下抛出异常,或者根据你认为合适的方式进行处理。

import { Err, Ok, Result } from 'ts-results'

export function bigIntToNumber(value: bigint): Result<number, Error> {
  if (validInterger(value)) {
    return Ok(Number(value))
  }

  return Err(new Error(`Value: "${value}" is out of bounds to be a Number`))
}

function validInteger(value: bigint): boolean {
  return value <= Number.MAX_SAFE_INTEGER && value >= Number.MIN_SAFE_INTEGER
}

关于数据类型和数据范围的一些说明

有趣的是,JS的数字可以达到9,007,199,254,740,991(即Number.MAX_SAFE_INTEGER),而经典的4字节整数只能达到2,147,483,647,因此JS的数字可以容纳更多,但不及8字节整数,后者可以达到9,223,372,036,854,775,807

正如评论中所指出的,超过Number.MAX_SAFE_INTEGER的数字可以达到Number.MAX_VALUE,仍然是有效的JS数字。您可以在这里阅读更多信息:


您的最后一段,目前的措辞是不正确的。例如,10_000_000_000_000_000_000 完全是一个有效的JS数字。我知道你的意思(2**53 - 12**31 - 12**63 - 1 之间,当然!),但这不是目前那段话的意思。另一种表达方式是:Number.MAX_SAFE_INTEGER 不等于 Number.MAX_VALUE。您谈论的是前者,但JS数字“可以达到”(或“可以容纳”)后者。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接