JavaScript 中引入 BigInt
的提案,主要是为了解决Number
类型在表示和操作大整数时的精度限制问题。
核心原因:Number
类型的精度限制
在 JavaScript 中,所有的数字(包括整数和浮点数)都使用 IEEE 754 双精度 64 位浮点数格式存储。这种格式虽然能表示很大的数值范围,但整数的安全范围是有限的。
1. Number.MAX_SAFE_INTEGER
- JavaScript 能精确表示的最大整数是
2^53 - 1
,即9,007,199,254,740,991
。 - 超过这个值的整数,精度会丢失。
console.log(Number.MAX_SAFE_INTEGER); // 9007199254740991
console.log(Number.MAX_SAFE_INTEGER + 1); // 9007199254740992
console.log(Number.MAX_SAFE_INTEGER + 2); // 9007199254740992 ← 和上面一样!精度丢失
2. 实际问题场景
在以下场景中,需要处理超过 Number.MAX_SAFE_INTEGER
的整数:
- 金融计算:处理高精度金额、大额交易、加密货币(如比特币的 satoshi 单位)。
- 数据库主键:许多数据库(如 MySQL 的
BIGINT
)使用 64 位整数作为主键,其范围远超Number.MAX_SAFE_INTEGER
。 - 科学计算:处理大数运算、密码学算法(如 RSA)。
- 时间戳:某些系统使用纳秒级时间戳,可能超出安全整数范围。
- 唯一标识符:如 Twitter 的 Snowflake ID、分布式系统的唯一 ID。
// 一个常见的问题:数据库 ID 被错误地“四舍五入”
const userId = 9007199254740993; // 数据库中的真实 ID
const jsonStr = JSON.stringify({ id: userId });
// JSON.stringify 会将其转换为字符串?不,它会尝试保留为数字,但精度已丢失
const parsed = JSON.parse(jsonStr);
console.log(parsed.id); // 9007199254740992 ← 错误的 ID!可能导致安全或数据问题
BigInt
的解决方案
BigInt
是一种新的原始数据类型(primitive type),用于表示任意精度的整数。
如何使用
- 在整数字面量后加
n
:123n
- 使用
BigInt()
构造函数:BigInt("123")
const bigInt1 = 9007199254740993n;
const bigInt2 = BigInt("9007199254740993");
console.log(bigInt1 === bigInt2); // true
console.log(bigInt1 + 1n); // 9007199254740994n ← 精确计算
BigInt
的特点
- 可以表示任意大的整数(只受内存限制)。
- 与
Number
不兼容:不能直接与Number
进行混合运算。 - 不能使用
Math
对象中的方法。 - 不能转换为
Number
(使用Number(bigInt)
会抛出错误)。 - 在
JSON.stringify
中不被原生支持(需要自定义toJSON
方法)。
// 错误:混合运算
// 1 + 1n; // TypeError
// 正确:类型一致
1n + 1n; // 2n
总结
问题 | 回答 |
---|---|
为什么有 BigInt 提案? | 因为 Number 类型无法安全表示超过 2^53 - 1 的整数,导致精度丢失。现代应用(如金融、数据库、加密)需要处理大整数,因此需要 BigInt 来提供任意精度的整数支持。 |
BigInt
的引入,使 JavaScript 能够更安全、精确地处理大整数运算,填补了语言在数值处理上的关键空白。
THE END