各位靓仔靓女,老少爷们,大家好!今天咱来聊聊JavaScript里的“大块头”—— BigInt
。这玩意儿啊,说白了,就是用来解决JavaScript处理整数精度问题的一把利器。
开场白:为啥我们需要 BigInt
?
话说当年,JavaScript它老人家出生的时候,也没想到自己能火成这样。那时候,它定义数字就用一个 Number
类型,基于 IEEE 754 双精度浮点数标准。这标准吧,好处是能表示小数,坏处是整数的精度有限。它能精确表示的整数范围是 -253 到 253 – 1,也就是大约 -9千万亿到 9千万亿之间。
超过这个范围咋办?凉拌呗!JavaScript会默默地帮你进行近似,结果就变成了“不是你想要的结果”。比如说:
console.log(Number.MAX_SAFE_INTEGER); // 9007199254740991
console.log(Number.MAX_SAFE_INTEGER + 1); // 9007199254740992
console.log(Number.MAX_SAFE_INTEGER + 2); // 9007199254740992 (WTF? 期望是9007199254740993啊!)
看见没?加2的结果跟加1一样!这要是用在金融计算、密码学、或者其他需要精确整数的场景,那可就翻车了。所以,BigInt
就应运而生了,专门来拯救这些“大”数字。
BigInt
:闪亮登场!
BigInt
是 ES2020 引入的新类型,它允许我们安全地存储和操作任意大小的整数。记住,是任意大小!只要你内存够大,多大的数都能hold住。
创建 BigInt
的两种姿势
-
数字后面加
n
: 这是最简单粗暴的方式。const bigNumber = 12345678901234567890n; console.log(bigNumber); // 12345678901234567890n console.log(typeof bigNumber); // bigint
-
使用
BigInt()
构造函数: 这种方式更灵活,可以把字符串或者数字转换成BigInt
。const bigNumberFromString = BigInt("98765432109876543210"); const bigNumberFromNumber = BigInt(123); //小心使用,超过安全范围的number转换可能不精确 console.log(bigNumberFromString); // 98765432109876543210n console.log(bigNumberFromNumber); // 123n
注意: 使用
BigInt()
构造函数从Number
创建BigInt
时要小心。如果Number
超出了安全整数范围,转换的结果可能是不精确的。最好是从字符串创建。
BigInt
的运算:小心有坑!
BigInt
支持大部分的算术运算符,比如 +
、-
、*
、/
、%
、**
。 但是,要注意以下几点:
-
BigInt
只能和BigInt
运算: 不能直接和普通的Number
类型混着算。如果你非要混着算,JavaScript会毫不留情地抛出一个TypeError
。const bigNumber = 10n; const regularNumber = 5; //console.log(bigNumber + regularNumber); // TypeError: Cannot mix BigInt and other types // 必须先转换成同一种类型才能运算 console.log(bigNumber + BigInt(regularNumber)); // 15n console.log(Number(bigNumber) + regularNumber); // 15
-
除法会向下取整:
BigInt
的除法结果会舍弃小数部分,只保留整数部分。const a = 10n; const b = 3n; console.log(a / b); // 3n (不是 3.3333...)
-
位运算符:
BigInt
支持位运算符,如&
(按位与),|
(按位或),^
(按位异或),~
(按位非),<<
(左移),>>
(右移)。const x = 5n; // 二进制 101 const y = 3n; // 二进制 011 console.log(x & y); // 1n (二进制 001) console.log(x | y); // 7n (二进制 111) console.log(x ^ y); // 6n (二进制 110) console.log(x << 1n); // 10n (二进制 1010) console.log(x >> 1n); // 2n (二进制 010)
-
比较运算符:
BigInt
可以使用比较运算符,如==
,===
,!=
,!==
,<
,>
,<=
,>=
。BigInt
和Number
在进行松散相等 (==
) 比较时,会进行类型转换。 但是,强烈建议使用严格相等 (===
) 避免意外的类型转换。console.log(10n == 10); // true console.log(10n === 10); // false console.log(10n > 5); // true console.log(5n > 10); // false
-
一元取正/取反运算符: BigInt 支持一元取正 (
+
) 和取反 (-
) 运算符。const a = 5n; console.log(+a); // 5n console.log(-a); // -5n
BigInt
的一些常用方法
BigInt
本身没有太多内置方法,但可以结合其他JavaScript特性进行操作。
-
转换为字符串: 使用
String()
或者toString()
方法将BigInt
转换为字符串。const bigNumber = 12345678901234567890n; const str = String(bigNumber); console.log(str); // "12345678901234567890"
-
转换为
Number
(要小心): 可以使用Number()
将BigInt
转换为Number
。 但是! 如果BigInt
的值超出了Number
的安全整数范围,转换的结果会失去精度。所以,除非你确定BigInt
的值在安全范围内,否则不要轻易转换。const safeBigNumber = 100n; const unsafeBigNumber = 9007199254740992n; // 超过安全范围 console.log(Number(safeBigNumber)); // 100 console.log(Number(unsafeBigNumber)); // 9007199254740992 (看似一样,但可能不精确) console.log(Number(unsafeBigNumber + 1n)); // 9007199254740992 (精度丢失了!)
BigInt
的应用场景
-
金融计算: 处理货币、股票等需要高精度计算的场景。
-
密码学: 在加密算法中,经常需要处理大整数。
-
科学计算: 某些科学计算需要处理超出
Number
安全范围的整数。 -
ID生成: 生成全局唯一ID,避免ID冲突。
-
大型游戏: 一些大型游戏,比如区块链游戏,需要处理大量的数字。
BigInt
的一些限制
-
不能用于
Math
对象的方法:Math.sqrt()
,Math.pow()
等方法不支持BigInt
。 你需要自己实现这些方法或者使用第三方库。 -
JSON 序列化/反序列化: 默认情况下,
JSON.stringify()
不支持BigInt
。 你需要自己实现序列化和反序列化的逻辑。 一个常见的做法是将BigInt
转换为字符串。const bigNumber = 12345678901234567890n; const json = JSON.stringify({ value: bigNumber.toString() }); // 转换为字符串 console.log(json); // {"value":"12345678901234567890"} const parsed = JSON.parse(json, (key, value) => { if (key === 'value') { return BigInt(value); // 转换回 BigInt } return value; }); console.log(parsed.value); // 12345678901234567890n
-
浏览器兼容性: 虽然
BigInt
是ES2020标准,但仍然需要考虑浏览器的兼容性。 对于不支持BigInt
的浏览器,你需要使用polyfill或者使用其他替代方案。
代码示例:斐波那契数列
用 BigInt
计算斐波那契数列,妈妈再也不用担心我溢出了!
function fibonacci(n) {
if (n <= 1) {
return BigInt(n);
}
let a = 0n;
let b = 1n;
for (let i = 2; i <= n; i++) {
const temp = a + b;
a = b;
b = temp;
}
return b;
}
console.log(fibonacci(10)); // 55n
console.log(fibonacci(50)); // 12586269025n
console.log(fibonacci(100)); // 354224848179261915075n
总结:BigInt
的优缺点
特性 | 优点 | 缺点 |
---|---|---|
精度 | 可以精确表示任意大小的整数,避免了 Number 类型的精度问题。 |
性能比 Number 慢,因为需要更多的内存和计算资源。 |
运算 | 支持大部分的算术运算符和位运算符。 | 不能直接和 Number 类型混合运算,需要进行类型转换。 除法会向下取整。 不能用于 Math 对象的方法。 |
应用场景 | 金融计算、密码学、科学计算、ID生成、大型游戏等需要高精度整数的场景。 | JSON 序列化/反序列化需要特殊处理。 浏览器兼容性需要考虑。 |
使用方式 | 简单易用,可以通过在数字后面加 n 或者使用 BigInt() 构造函数创建。 |
从 Number 创建 BigInt 时要小心,如果 Number 超出了安全整数范围,转换的结果可能是不精确的。 |
彩蛋:BigInt
和 Number
的爱恨情仇
BigInt
和 Number
就像一对欢喜冤家。 Number
擅长处理小数和中小型的整数,速度快,效率高。 BigInt
擅长处理超大整数,精度高,但速度稍慢。 它们各有优缺点,在不同的场景下发挥着不同的作用。
在选择使用 BigInt
还是 Number
时,要根据实际需求进行权衡。 如果你需要处理的整数超出了 Number
的安全范围,或者需要高精度的计算,那么 BigInt
是你的不二之选。 如果你只需要处理中小型的整数,并且对性能有较高的要求,那么 Number
仍然是更好的选择。
总结一下:
BigInt
虽好,但也要注意使用场景和限制。 只有在真正需要处理大整数的时候,才应该考虑使用它。 不要为了用而用,否则可能会适得其反。
好了,今天的 BigInt
讲座就到这里。 希望大家以后在遇到需要处理大整数的场景时,能够想起我今天讲的内容,并且能够熟练地运用 BigInt
,写出更加健壮和可靠的代码。
散会! 祝大家编码愉快!