BigInt

Baseline Widely available

This feature is well established and works across many devices and browser versions. It’s been available across browsers since September 2020.

BigInt 值代表数值,而 太大了 则由 numberprimitive 代表。

¥**BigInt** values represent numeric values which are too large to be represented by the number primitive.

描述

¥Description

BigInt 值(有时也简称为 BigInt)是 bigint primitive,通过将 n 附加到整数文字的末尾,或通过调用 BigInt() 函数(不带 new 运算符)并为其指定整数值或字符串值来创建。

¥A BigInt value, also sometimes just called a BigInt, is a bigint primitive, created by appending n to the end of an integer literal, or by calling the BigInt() function (without the new operator) and giving it an integer value or string value.

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 值时可能会丢失精度。

¥BigInt values are similar to Number values in some ways, but also differ in a few key matters: A BigInt value cannot be used with methods in the built-in Math object and cannot be mixed with a Number value in operations; they must be coerced to the same type. Be careful coercing values back and forth, however, as the precision of a BigInt value may be lost when it is coerced to a Number value.

类型信息

¥Type information

当针对 typeof 进行测试时,BigInt 值(bigint 原语)将给出 "bigint"

¥When tested against typeof, a BigInt value (bigint primitive) will give "bigint":

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

BigInt 值也可以封装在 Object 中:

¥A BigInt value can also be wrapped in an Object:

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

运算符

¥Operators

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

¥Most operators support BigInts, however most do not permit operands to be of mixed types — both operands must be BigInt or neither:

布尔返回运算符允许混合数字和 BigInt 作为操作数:

¥The boolean-returning operators allow mixing numbers and BigInts as operands:

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

¥A couple of operators do not support BigInt at all:

特别案例:

¥Special cases:

  • 涉及字符串和 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

比较

¥Comparisons

BigInt 值并不严格等于 Number 值,但大致如此:

¥A BigInt value is not strictly equal to a Number value, but it is loosely so:

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

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

¥A Number value and a BigInt value may be compared as usual:

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

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

¥BigInt values and Number values may be mixed in arrays and sorted:

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 值的比较与其他对象的比较一样,仅在比较同一对象实例时指示相等:

¥Note that comparisons with Object-wrapped BigInt values act as with other objects, only indicating equality when the same object instance is compared:

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

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

由于 Number 值和 BigInt 值之间的强制转换可能会导致精度损失,因此建议采用以下方法:

¥Because coercing between Number values and BigInt values can lead to loss of precision, the following are recommended:

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

条件句

¥Conditionals

在以下情况下,BigInt 值遵循与 Number 相同的转换规则:

¥A BigInt value follows the same conversion rules as Numbers when:

即只有 0nfalsy;其他一切都是 truthy

¥Namely, only 0n is falsy; everything else is truthy.

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

密码学

¥Cryptography

BigInt 值支持的操作不是恒定时间的,因此对 定时攻击 开放。因此,如果没有缓解因素,JavaScript BigInts 在密码学中使用可能会很危险。作为一个非常通用的示例,攻击者可以测量 101n ** 65537n17n ** 9999n 之间的时间差,并根据经过的时间推断出秘密(例如私钥)的大小。如果你仍然需要使用 BigInts,请查看 定时攻击常见问题解答 以获取有关该问题的一般建议。

¥The operations supported on BigInt values are not constant-time and are thus open to timing attacks. JavaScript BigInts therefore could be dangerous for use in cryptography without mitigating factors. As a very generic example, an attacker could measure the time difference between 101n ** 65537n and 17n ** 9999n, and deduce the magnitude of secrets, such as private keys, based on the time elapsed. If you still have to use BigInts, take a look at the Timing attack FAQ for general advice regarding the issue.

在 JSON 中使用

¥Use within JSON

JSON.stringify() 与任何 BigInt 值一起使用都会引发 TypeError,因为默认情况下 BigInt 值不会在 JSON 中序列化。然而,JSON.stringify() 专门为 BigInt 值留下了后门:它会尝试调用 BigInt 的 toJSON() 方法。(它不会对任何其他原始值执行此操作。)因此,你可以实现自己的 toJSON() 方法(这是不明确阻止修补内置对象的少数情况之一):

¥Using JSON.stringify() with any BigInt value will raise a TypeError, as BigInt values aren't serialized in JSON by default. However, JSON.stringify() specifically leaves a backdoor for BigInt values: it would try to call the BigInt's toJSON() method. (It doesn't do so for any other primitive values.) Therefore, you can implement your own toJSON() method (which is one of the few cases where patching built-in objects is not explicitly discouraged):

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

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

¥Instead of throwing, JSON.stringify() now produces a string like this:

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

如果你不想修补 BigInt.prototype,可以使用 JSON.stringifyreplacer 参数来序列化 BigInt 值:

¥If you do not wish to patch BigInt.prototype, you can use the replacer parameter of JSON.stringify to serialize BigInt values:

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 参数来处理它们:

¥You can then use the reviver parameter of JSON.parse to handle them:

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() 的替换程序通用并正确序列化所有对象的 BigInt 值(如上所示),但必须谨慎使用 JSON.parse() 的恢复程序,因为序列化是有损的:无法区分恰好具有名为 $bigint 的属性的对象和实际的 BigInt。

¥Note: While it's possible to make the replacer of JSON.stringify() generic and properly serialize BigInt values for all objects as shown above, the reviver of JSON.parse() has to be used with caution, because the serialization is lossy: it's not possible to distinguish between an object that happens to have a property called $bigint and an actual BigInt.

此外,上面的示例在替换和恢复期间创建了整个对象,这可能会对包含许多 BigInt 的较大对象产生性能或存储影响。如果你知道有效负载的形状,最好将它们序列化为字符串并根据属性键的名称恢复它们。

¥In addition, the example above creates an entire object during replacing and reviving, which may have performance or storage implications for larger objects containing many BigInts. If you know the shape of the payload, it may be better to just serialize them as strings and revive them based on the property key's name instead.

事实上,JSON 允许任意长的数字文字;它们只是无法在 JavaScript 中被完全精确地解析。如果你正在使用支持较长整数(例如 64 位整数)的语言与另一个程序进行通信,并且你希望将 BigInt 作为 JSON 数字而不是 JSON 字符串进行传输,请参阅 无损数字序列化

¥In fact, JSON allows number literals that are arbitrarily long; they just cannot be parsed to full precision in JavaScript. If you are communicating with another program in a language that supports longer integers (such as 64-bit integers), and you want to transmit the BigInt as a JSON number instead of a JSON string, see Lossless number serialization.

BigInt 强制转换

¥BigInt coercion

许多期望 BigInts 的内置操作首先将其参数强制为 BigInts。操作 可概括如下:

¥Many built-in operations that expect BigInts first coerce their arguments to BigInts. The operation can be summarized as follows:

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

¥The best way to achieve nearly the same effect in JavaScript is through the BigInt() function: BigInt(x) uses the same algorithm to convert x, except that Numbers don't throw a TypeError, but are converted to BigInts if they are integers.

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

¥Note that built-in operations expecting BigInts often truncate the BigInt to a fixed width after coercion. This includes BigInt.asIntN(), BigInt.asUintN(), and methods of BigInt64Array and BigUint64Array.

构造函数

¥Constructor

BigInt()

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

静态方法

¥Static methods

BigInt.asIntN()

将 BigInt 值钳位为有符号整数值,并返回该值。

BigInt.asUintN()

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

实例属性

¥Instance properties

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

¥These properties are defined on BigInt.prototype and shared by all BigInt instances.

BigInt.prototype.constructor

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

BigInt.prototype[Symbol.toStringTag]

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

实例方法

¥Instance methods

BigInt.prototype.toLocaleString()

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

BigInt.prototype.toString()

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

BigInt.prototype.valueOf()

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

示例

¥Examples

计算素数

¥Calculating Primes

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

规范

Specification
ECMAScript Language Specification
# sec-bigint-objects

¥Specifications

浏览器兼容性

BCD tables only load in the browser

¥Browser compatibility

也可以看看