JavaScript BigInt

原创
admin 4个月前 (08-19) 阅读数 19 #JavaScript

BigInt:JavaScript中的大整数处理

BigInt是JavaScript中的一种内置对象,它提供了一种方法来表示大于2^53 - 1的整数。这原本是JavaScript中可以用Number表示的最大数字。BigInt可以表示任意大的整数,为开发者处理大数值提供了便利。

BigInt的定义与创建

可以通过在整数字面量后面加n的方式定义一个BigInt,如10n,或者调用函数BigInt()(但不包含new运算符)并传递一个整数值或字符串值。

const theBiggestInt = 9007199254740991n;

const alsoHuge = BigInt(9007199254740991);
// ↪ 9007199254740991n

const hugeString = BigInt("9007199254740991");
// ↪ 9007199254740991n

const hugeHex = BigInt("0x1fffffffffffff");
// ↪ 9007199254740991n

const hugeBin = BigInt(
  "0b11111111111111111111111111111111111111111111111111111",
);
// ↪ 9007199254740991n

BigInt在某些方面类似于Number,但是也有几个关键的不同点:不能用于Math对象中的方法;不能和任何Number实例混合运算,两者必须转换成同一种类型。在两种类型来回转换时要小心,因为BigInt变量在转换成Number变量时可能会丢失精度。

类型信息

使用typeof测试时,BigInt对象返回"bigint":

typeof 1n === "bigint"; // true
typeof BigInt("1") === "bigint"; // true

使用Object包装后,BigInt被认为是一个普通"object":

typeof Object(1n) === "object"; // true

BigInt的运算

以下操作符可以和BigInt一起使用:+、*、-、**、%。除>>>(无符号右移)之外的位操作也可以支持。因为BigInt都是有符号的,>>>(无符号右移)不能用于BigInt。为了兼容asm.js,BigInt不支持单目(+)运算符。

const previousMaxSafe = BigInt(Number.MAX_SAFE_INTEGER);
// ↪ 9007199254740991n

const maxPlusOne = previousMaxSafe + 1n;
// ↪ 9007199254740992n

const theFuture = previousMaxSafe + 2n;
// ↪ 9007199254740993n, this works now!

const multi = previousMaxSafe * 2n;
// ↪ 18014398509481982n

const subtr = multi - 10n;
// ↪ 18014398509481972n

const mod = multi % 10n;
// ↪ 2n

const bigN = 2n ** 54n;
// ↪ 18014398509481984n

bigN * -1n
// ↪ -18014398509481984n

/操作符对于整数的运算也没问题。可是因为这些变量是BigInt而不是BigDecimal,该操作符结果会向零取整,也就是说不会返回小数部分。

警告:当使用BigInt时,带小数的运算会被取整。

const expected = 4n / 2n;
// ↪ 2n

const rounded = 5n / 2n;
// ↪ 2n, not 2.5n

比较操作

BigInt和Number不是严格相等的,但是宽松相等的。

0n === 0;
// ↪ false

0n == 0;
// ↪ true

Number和BigInt可以进行各种比较操作:

1n < 2;
// ↪ true

2n > 1;
// ↪ true

2 > 2;
// ↪ false

2n > 2;
// ↪ false

2n >= 2;
// ↪ true

两者也可以混在一个数组内并排序。

const mixed = [4n, 6, -12n, 10, 4, 0, 0n];
// ↪  [4n, 6, -12n, 10, 4, 0, 0n]

mixed.sort();
// ↪ [-12n, 0, 0n, 10, 4n, 4, 6]

注意被Object包装的BigInt使用object的比较规则进行比较,只用同一个对象在比较时才会相等。

条件判断

BigInt在需要转换成Boolean时表现跟Number类似:如通过Boolean函数转换;用于逻辑运算||、&&和!的操作数;或者用于在if语句这样的条件语句中。

if (0n) {
  console.log("Hello from the if!");
} else {
  console.log("Hello from the else!");
}

// ↪ "Hello from the else!"

0n || 12n;
// ↪ 12n

0n && 12n;
// ↪ 0n

Boolean(0n);
// ↪ false

Boolean(12n);
// ↪ true

!12n;
// ↪ false

!0n;
// ↪ true

BigInt的构造器与静态方法

BigInt()构造函数用于创建BigInt对象。

BigInt.asIntN()静态方法将BigInt值转换为一个-2^(width-1)与2^(width-1)-1之间的有符号整数。

BigInt.asUintN()静态方法将一个BigInt值转换为0与2^(width)-1之间的无符号整数。

BigInt的实例方法

BigInt.prototype.toLocaleString()返回此数字的language-sensitive形式的字符串,覆盖Object.prototype.toLocaleString()方法。

BigInt.prototype.toString()返回以指定基数(base)表示指定数字的字符串,覆盖Object.prototype.toString()方法。

BigInt.prototype.valueOf()返回指定对象的基元值,覆盖Object.prototype.valueOf()方法。

使用建议

类型转换

由于在Number与BigInt之间进行转换会损失精度,因而建议仅在值可能大于2^53时使用BigInt类型,并且不在两种类型之间进行相互转换。

密码学应用

由于对BigInt的操作不是常数时间的,因而BigInt不适合用于密码学。

在JSON中使用

对任何BigInt值使用JSON.stringify()都会引发TypeError,因为默认情况下BigInt值不会在JSON中序列化。但是,如果需要,可以实现toJSON方法:

BigInt.prototype.toJSON = function () {
  return this.toString();
};

JSON.stringify现在生成如下字符串,而不是抛出异常:

JSON.stringify(BigInt(1));
// '"1"'

实际应用示例:计算质数

function isPrime(n) {
  if (n < 2n) {
    return false;
  }
  if (n % 2n === 0n) {
    return n === 2n;
  }
  for (let factor = 3n; factor * factor <= n; factor += 2n) {
    if (n % factor === 0n) {
      return false;
    }
  }
  return true;
}

// 接收一个BigInt值参数,以BigInt值返回第n个质数值
function nthPrime(nth) {
  let maybePrime = 2n;
  let prime = 0n;
  while (nth >= 0n) {
    if (isPrime(maybePrime)) {
      nth--;
      prime = maybePrime;
    }
    maybePrime++;
  }
  return prime;
}
nthPrime(20n);
// 73n

备注:isPrime()实现仅供演示。在实际应用中,为了避免重复计算,会使用大量记忆化的算法,例如埃拉托斯特尼筛法。

相关规范

BigInt的规范定义在ECMAScript® 2026 Language Specification中的BigInt Objects部分。

参见

  • Number
版权声明

本文仅代表作者观点,不代表本站立场。
本文系作者授权本站发表,未经许可,不得转载。

上一篇:JavaScript原子 下一篇:JavaScript BigInt64Array
作者文章
热门
最新文章
标签列表