跳到主要内容

JavaScript BigInt

什么是 BigInt?

在 JavaScript 中,标准的 Number 类型只能安全地表示范围在 -(2^53 - 1) 到 (2^53 - 1) 之间的整数,即大约 -9007199254740991 到 9007199254740991 之间的数值。这个限制在大多数日常应用中并不明显,但在处理非常大的整数时(如加密、时间戳的微秒表示或某些科学计算)会成为问题。

ES2020 引入了 BigInt,这是 JavaScript 的第七种基本数据类型,专门用于表示任意精度的整数。无论多大的整数,BigInt 都能准确表示,不会有精度损失。

BigInt 的基本使用

创建 BigInt

有两种方法可以创建 BigInt:

  1. 在数字末尾添加 n
javascript
const bigNumber = 9007199254740991n;
console.log(bigNumber); // 输出: 9007199254740991n
  1. 使用 BigInt() 构造函数:
javascript
const anotherBigNumber = BigInt("9007199254740991");
console.log(anotherBigNumber); // 输出: 9007199254740991n

// 也可以直接传入数字
const yetAnotherBigNumber = BigInt(9007199254740991);
console.log(yetAnotherBigNumber); // 输出: 9007199254740991n
备注

当使用 BigInt() 构造函数时,你可以传入一个数字或一个表示数字的字符串。

BigInt 的表现形式

BigInt 在打印时会在末尾显示 n,这是为了区分它与普通数字:

javascript
console.log(10n); // 输出: 10n
console.log(typeof 10n); // 输出: "bigint"

BigInt 的操作

基本算术运算

BigInt 支持大多数标准的算术运算符:

javascript
console.log(10n + 20n); // 输出: 30n
console.log(10n - 5n); // 输出: 5n
console.log(10n * 10n); // 输出: 100n
console.log(10n / 3n); // 输出: 3n (注意: 结果会向零舍入)
console.log(10n % 3n); // 输出: 1n
console.log(10n ** 3n); // 输出: 1000n (10^3)
警告

BigInt 的除法结果会向零舍入,而不是像浮点数那样提供小数部分。这是因为 BigInt 专门用于表示整数。

比较运算

BigInt 可以与其他 BigInt 或 Number 类型比较:

javascript
console.log(10n === 10); // 输出: false (类型不同)
console.log(10n == 10); // 输出: true (值相等)
console.log(10n < 15); // 输出: true
console.log(10n > 5); // 输出: true
console.log(10n <= 10); // 输出: true

不支持的操作

BigInt 不支持某些操作,尤其是那些可能导致非整数结果的操作:

javascript
// 这些会抛出错误:
// console.log(10n + 10); // 错误: 不能混合 BigInt 和其他类型
// console.log(Math.sqrt(4n)); // 错误: BigInt 不能用于 Math 对象方法

要混合 BigInt 和普通数字进行运算,需要先进行转换:

javascript
console.log(10n + BigInt(10)); // 正确: 20n
console.log(Number(10n) + 10); // 正确: 20

// 但要注意可能的精度损失
const hugeBigInt = 9007199254740993n;
console.log(Number(hugeBigInt)); // 可能不精确: 9007199254740992

BigInt 的实际应用场景

1. 处理非常大的整数

javascript
// 计算大数的阶乘
function factorial(n) {
if (n === 0n) return 1n;
return n * factorial(n - 1n);
}

console.log(factorial(50n));
// 输出: 30414093201713378043612608166064768844377641568960512000000000000n

2. 高精度时间戳

当需要微秒级或纳秒级精度的时间戳时:

javascript
// 获取高精度时间戳(如果浏览器支持)
const start = BigInt(process.hrtime.bigint ? process.hrtime.bigint() : Date.now() * 1000000);

// 执行一些操作...

const end = BigInt(process.hrtime.bigint ? process.hrtime.bigint() : Date.now() * 1000000);
console.log(`操作耗时: ${end - start} 纳秒`);

3. 密码学和哈希函数

在加密应用中处理大整数:

javascript
// 简化的大整数幂模运算 (a^b mod n)
function modPow(base, exponent, modulus) {
if (modulus === 1n) return 0n;

let result = 1n;
base = base % modulus;

while (exponent > 0n) {
if (exponent % 2n === 1n) {
result = (result * base) % modulus;
}
exponent = exponent / 2n;
base = (base * base) % modulus;
}

return result;
}

// 在加密应用中可能会用到类似的计算
const publicKey = 65537n;
const modulus = 2305843009213693951n;
const message = 12345678901234567890n;

const encryptedMessage = modPow(message, publicKey, modulus);
console.log("加密后的消息:", encryptedMessage);

BigInt 的限制和注意事项

  1. JSON 序列化:BigInt 不能直接通过 JSON.stringify() 序列化:
javascript
const bigNum = 123456789012345678901234567890n;
// 这会抛出错误
// console.log(JSON.stringify({ bigNumber: bigNum }));

// 需要自定义转换
console.log(JSON.stringify({ bigNumber: bigNum.toString() }));
  1. 强制类型转换:转换为 Number 可能导致精度损失:
javascript
const bigNum = 9007199254740993n;
console.log(Number(bigNum)); // 可能不精确: 9007199254740992
  1. 小数点:BigInt 不支持小数点,它专注于表示整数:
javascript
// 这会抛出错误
// const invalidBigInt = 10.5n;
  1. Math 对象:BigInt 不能用于 Math 对象的方法:
javascript
// 这会抛出错误
// Math.max(1n, 2n);

性能考虑

BigInt 操作可能比常规数字操作慢,特别是当处理非常大的数字时。因此,只有在确实需要处理超过 Number 范围的整数时才使用 BigInt。

javascript
// 性能测试示例
function measurePerformance(fn, name) {
const start = performance.now();
fn();
const end = performance.now();
console.log(`${name} 耗时: ${end - start} 毫秒`);
}

// 使用普通数字
measurePerformance(() => {
let result = 1;
for (let i = 1; i <= 1000000; i++) {
result = (result * i) % 1000000007;
}
}, "Number 操作");

// 使用 BigInt
measurePerformance(() => {
let result = 1n;
for (let i = 1n; i <= 1000000n; i++) {
result = (result * i) % 1000000007n;
}
}, "BigInt 操作");

浏览器兼容性

BigInt 是相对较新的特性,在一些旧浏览器中可能不被支持。在使用前,可以检查环境是否支持:

javascript
if (typeof BigInt !== 'undefined') {
console.log("环境支持 BigInt!");
const bigNum = 123456789012345678901234567890n;
console.log(bigNum);
} else {
console.log("环境不支持 BigInt!");
}

总结

BigInt 是 JavaScript 中专门用于处理超出普通 Number 类型范围的大整数的数据类型。它为处理金融计算、密码学、高精度时间戳等场景提供了可能。

虽然 BigInt 有一些限制(如不支持小数、不能与 Math 对象一起使用等),但它是处理大整数时的理想选择。记住,在不需要处理超大整数时,出于性能考虑,普通 Number 类型仍然是首选。

练习和深入学习

  1. 尝试实现一个计算斐波那契大数列的函数,并计算第 1000 个斐波那契数。
  2. 编写一个函数,将一个非常大的十进制数转换为二进制表示。
  3. 实现一个简单的大整数计算器,支持加、减、乘、除和求幂操作。
  4. 研究如何在 Web 应用中安全地存储和传输 BigInt 值。

推荐资源

通过掌握 BigInt,你将能够处理 JavaScript 中前所未有的大整数计算,为你的应用打开新的可能性。