BigInt
描述
BigInt 值,有时也简称为 BigInt,是 bigint
原始类型,通过在整数字面量的末尾附加 n
创建,或者通过调用 BigInt()
函数(不使用 new
运算符)并向其提供整数或字符串值来创建。
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"
typeof 1n === "bigint"; // true
typeof BigInt("1") === "bigint"; // true
BigInt 值也可以包装在 Object
中
typeof Object(1n) === "object"; // true
运算符
大多数运算符都支持 BigInt,但是大多数运算符不允许操作数类型混合 - 两个操作数必须都是 BigInt 或都不是
返回布尔值的运算符允许将数字和 BigInt 作为操作数混合使用
有几个运算符根本不支持 BigInt
- 一元加 (
+
) 由于在 asm.js 中存在冲突的使用而无法支持,因此已将其排除在外 以避免破坏 asm.js。 - 无符号右移 (
>>>
) 是唯一不支持的位运算符,因为每个 BigInt 值都是有符号的。
特殊情况
- 涉及字符串和 BigInt 的加法 (
+
) 返回字符串。 - 除法 (
/
) 将小数部分截断为零,因为 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
const expected = 4n / 2n; // 2n
const truncated = 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
BigInt 值和 Number 值可以在数组中混合并排序
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 值的比较与其他对象的行为相同,仅在比较相同对象实例时才指示相等
Object(0n) === 0n; // false
Object(0n) === Object(0n); // false
const o = Object(0n);
o === o; // true
由于在 Number 值和 BigInt 值之间强制转换会导致精度丢失,因此建议执行以下操作
- 仅当合理预期大于 253 的值时,才使用 BigInt 值。
- 不要在 BigInt 值和 Number 值之间强制转换。
条件语句
当 BigInt 值转换为 Boolean
时,它遵循与数字相同的转换规则:
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 ** 65537n
和 17n ** 9999n
之间的时间差,并根据经过的时间推断秘密(如私钥)的幅度。如果您仍然必须使用 BigInt,请查看 时序攻击常见问题解答,以获取有关此问题的常规建议。
在 JSON 中使用
使用任何 BigInt 值的 JSON.stringify()
将引发 TypeError
,因为默认情况下 BigInt 值不会在 JSON 中序列化。但是,JSON.stringify()
特别地为 BigInt 值留了一个后门:它会尝试调用 BigInt 的 toJSON()
方法。(对于任何其他原始值,它都不会这样做。)因此,您可以实现自己的 toJSON()
方法(这是少数几个不显式不鼓励修补内置对象的案例之一)
BigInt.prototype.toJSON = function () {
return { $bigint: this.toString() };
};
现在,JSON.stringify()
不会抛出错误,而是会生成如下字符串
console.log(JSON.stringify({ a: 1n }));
// {"a":{"$bigint":"1"}}
如果您不希望修补 BigInt.prototype
,则可以使用 JSON.stringify
的 replacer
参数来序列化 BigInt 值
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.parse
的 reviver
参数来处理它们
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 原样返回。
undefined
和null
会抛出TypeError
。true
转换为1n
;false
转换为0n
。- 字符串通过将其解析为包含整数字面量的字符串来转换。任何解析失败都会导致
SyntaxError
。语法是 字符串数字字面量 的一个子集,其中不允许使用小数点或指数指示符。 - 数字 会抛出
TypeError
以防止意外的隐式强制转换导致精度损失。 - 符号 会抛出
TypeError
。 - 对象首先通过调用其 转换为基本类型
[Symbol.toPrimitive]()
(以"number"
作为提示)、valueOf()
和toString()
方法(按此顺序)来转换。然后将生成的原始值转换为 BigInt。
在 JavaScript 中实现几乎相同效果的最佳方法是通过 BigInt()
函数:BigInt(x)
使用相同的算法转换 x
,除了 数字 不会抛出 TypeError
,而是在它们是整数时转换为 BigInt。
请注意,期望 BigInt 的内置操作通常会在强制转换后将 BigInt 截断为固定宽度。这包括 BigInt.asIntN()
、BigInt.asUintN()
以及 BigInt64Array
和 BigUint64Array
的方法。
构造函数
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()
方法。
示例
计算素数
// 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 表格仅在浏览器中加载