BigInt

基线 广泛可用

此功能已完善,可在许多设备和浏览器版本上运行。它自以下时间起在浏览器中可用 2020 年 9 月.

BigInt 值表示数值,这些数值太大,无法用 number 原始类型 表示。

描述

BigInt 值,有时也简称为 BigInt,是 bigint 原始类型,通过在整数字面量的末尾附加 n 创建,或者通过调用 BigInt() 函数(不使用 new 运算符)并向其提供整数或字符串值来创建。

js
const previouslyMaxSafeInteger = 9007199254740991n;

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

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

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

const hugeOctal = BigInt("0o377777777777777777");
// 9007199254740991n

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

BigInt 值在某些方面与 Number 值类似,但在一些关键方面也存在差异:BigInt 值不能与内置 Math 对象中的方法一起使用,并且不能在运算中与 Number 值混合;它们必须强制转换为相同的类型。但是,请注意在强制转换值时要小心,因为当 BigInt 值强制转换为 Number 值时,可能会丢失精度。

类型信息

当针对 typeof 进行测试时,BigInt 值(bigint 原始类型)将返回 "bigint"

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

BigInt 值也可以包装在 Object

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

运算符

大多数运算符都支持 BigInt,但是大多数运算符不允许操作数类型混合 - 两个操作数必须都是 BigInt 或都不是

返回布尔值的运算符允许将数字和 BigInt 作为操作数混合使用

有几个运算符根本不支持 BigInt

特殊情况

  • 涉及字符串和 BigInt 的加法 (+) 返回字符串。
  • 除法 (/) 将小数部分截断为零,因为 BigInt 无法表示小数。
js
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
const expected = 4n / 2n; // 2n
const truncated = 5n / 2n; // 2n, not 2.5n

比较

BigInt 值与 Number 值不严格相等,但松散相等的

js
0n === 0; // false
0n == 0; // true

Number 值和 BigInt 值可以像往常一样进行比较

js
1n < 2; // true
2n > 1; // true
2 > 2; // false
2n > 2; // false
2n >= 2; // true

BigInt 值和 Number 值可以在数组中混合并排序

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

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

mixed.sort((a, b) => a - b);
// won't work since subtraction will not work with mixed types
// TypeError: can't convert BigInt value to Number value

// sort with an appropriate numeric comparator
mixed.sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));
// [ -12n, 0, 0n, 4n, 4, 6, 10 ]

请注意,与 Object 包装的 BigInt 值的比较与其他对象的行为相同,仅在比较相同对象实例时才指示相等

js
Object(0n) === 0n; // false
Object(0n) === Object(0n); // false

const o = Object(0n);
o === o; // true

由于在 Number 值和 BigInt 值之间强制转换会导致精度丢失,因此建议执行以下操作

  • 仅当合理预期大于 253 的值时,才使用 BigInt 值。
  • 不要在 BigInt 值和 Number 值之间强制转换。

条件语句

当 BigInt 值转换为 Boolean 时,它遵循与数字相同的转换规则:

  • 通过 Boolean 函数;
  • 当与 逻辑运算符 ||&&! 一起使用时;或者
  • 在条件测试中(例如 if 语句)中。

即,只有 0n假值;其他所有值都是 真值

js
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 值上支持的操作不是恒定时间的,因此容易受到 时序攻击。因此,JavaScript BigInt 在没有缓解因素的情况下可能对用于密码学存在危险。作为一个非常通用的示例,攻击者可以测量 101n ** 65537n17n ** 9999n 之间的时间差,并根据经过的时间推断秘密(如私钥)的幅度。如果您仍然必须使用 BigInt,请查看 时序攻击常见问题解答,以获取有关此问题的常规建议。

在 JSON 中使用

使用任何 BigInt 值的 JSON.stringify() 将引发 TypeError,因为默认情况下 BigInt 值不会在 JSON 中序列化。但是,JSON.stringify() 特别地为 BigInt 值留了一个后门:它会尝试调用 BigInt 的 toJSON() 方法。(对于任何其他原始值,它都不会这样做。)因此,您可以实现自己的 toJSON() 方法(这是少数几个不显式不鼓励修补内置对象的案例之一)

js
BigInt.prototype.toJSON = function () {
  return { $bigint: this.toString() };
};

现在,JSON.stringify() 不会抛出错误,而是会生成如下字符串

js
console.log(JSON.stringify({ a: 1n }));
// {"a":{"$bigint":"1"}}

如果您不希望修补 BigInt.prototype,则可以使用 JSON.stringifyreplacer 参数来序列化 BigInt 值

js
const replacer = (key, value) =>
  typeof value === "bigint" ? { $bigint: value.toString() } : value;

const data = {
  number: 1,
  big: 18014398509481982n,
};
const stringified = JSON.stringify(data, replacer);

console.log(stringified);
// {"number":1,"big":{"$bigint":"18014398509481982"}}

然后,您可以使用 JSON.parsereviver 参数来处理它们

js
const reviver = (key, value) =>
  value !== null &&
  typeof value === "object" &&
  "$bigint" in value &&
  typeof value.$bigint === "string"
    ? BigInt(value.$bigint)
    : value;

const payload = '{"number":1,"big":{"$bigint":"18014398509481982"}}';
const parsed = JSON.parse(payload, reviver);

console.log(parsed);
// { number: 1, big: 18014398509481982n }

注意:虽然可以使 JSON.stringify() 的 replacer 通用并正确地序列化所有对象的 BigInt 值(如上所示),但必须谨慎使用 JSON.parse() 的 reviver,因为序列化是不可逆的:无法区分碰巧具有名为 $bigint 的属性的对象和实际的 BigInt。

此外,上述示例在替换和恢复期间创建了整个对象,对于包含许多 BigInt 的大型对象,这可能会对性能或存储造成影响。如果您知道有效负载的结构,则最好将其序列化为字符串,并根据属性键的名称恢复它们。

事实上,JSON 允许任意长的数字字面量;它们只是无法在 JavaScript 中以完全精度解析。如果您正在与支持更长整数(例如 64 位整数)的其他语言的程序通信,并且希望将 BigInt 作为 JSON 数字而不是 JSON 字符串传输,请参阅无损数字序列化

BigInt 强制转换

许多期望 BigInt 的内置操作首先将其参数强制转换为 BigInt。该操作 可以概括如下

  • BigInt 原样返回。
  • undefinednull 会抛出 TypeError
  • true 转换为 1nfalse 转换为 0n
  • 字符串通过将其解析为包含整数字面量的字符串来转换。任何解析失败都会导致 SyntaxError。语法是 字符串数字字面量 的一个子集,其中不允许使用小数点或指数指示符。
  • 数字 会抛出 TypeError 以防止意外的隐式强制转换导致精度损失。
  • 符号 会抛出 TypeError
  • 对象首先通过调用其 转换为基本类型 [Symbol.toPrimitive]()(以 "number" 作为提示)、valueOf()toString() 方法(按此顺序)来转换。然后将生成的原始值转换为 BigInt。

在 JavaScript 中实现几乎相同效果的最佳方法是通过 BigInt() 函数:BigInt(x) 使用相同的算法转换 x,除了 数字 不会抛出 TypeError,而是在它们是整数时转换为 BigInt。

请注意,期望 BigInt 的内置操作通常会在强制转换后将 BigInt 截断为固定宽度。这包括 BigInt.asIntN()BigInt.asUintN() 以及 BigInt64ArrayBigUint64Array 的方法。

构造函数

BigInt()

返回 BigInt 类型的原始值。当使用 new 调用时会抛出错误。

静态方法

BigInt.asIntN()

将 BigInt 值钳位到带符号整数值,并返回该值。

BigInt.asUintN()

将 BigInt 值钳位到无符号整数值,并返回该值。

实例属性

这些属性定义在 BigInt.prototype 上,并由所有 BigInt 实例共享。

BigInt.prototype.constructor

创建实例对象的构造函数。对于 BigInt 实例,初始值为 BigInt 构造函数。

BigInt.prototype[Symbol.toStringTag]

[Symbol.toStringTag] 属性的初始值为字符串 "BigInt"。此属性用于 Object.prototype.toString()。但是,由于 BigInt 也有自己的 toString() 方法,因此除非您使用 BigInt 作为 thisArg 调用 Object.prototype.toString.call(),否则不会使用此属性。

实例方法

BigInt.prototype.toLocaleString()

返回包含此 BigInt 值的语言敏感表示形式的字符串。覆盖 Object.prototype.toLocaleString() 方法。

BigInt.prototype.toString()

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

BigInt.prototype.valueOf()

返回此 BigInt 值。覆盖 Object.prototype.valueOf() 方法。

示例

计算素数

js
// Returns true if the passed BigInt value is a prime number
function isPrime(p) {
  for (let i = 2n; i * i <= p; i++) {
    if (p % i === 0n) return false;
  }
  return true;
}

// Takes a BigInt value as an argument, returns nth prime number as a BigInt value
function nthPrime(nth) {
  let maybePrime = 2n;
  let prime = 0n;

  while (nth >= 0n) {
    if (isPrime(maybePrime)) {
      nth--;
      prime = maybePrime;
    }
    maybePrime++;
  }

  return prime;
}

nthPrime(20n);
// 73n

规范

规范
ECMAScript 语言规范
# sec-bigint-objects

浏览器兼容性

BCD 表格仅在浏览器中加载

另请参阅