各位靓仔靓女,晚上好!我是今晚的JS讲师,很高兴能和大家一起聊聊JavaScript的BigInt
,以及在处理大数运算时,如何通过polyfill
来让老浏览器也能用上这个新特性。准备好了吗?Let’s go!
第一部分:BigInt
是个啥?为啥需要它?
话说,在JavaScript的世界里,数字可不是你想多大就多大。它有一个安全整数范围,也就是Number.MAX_SAFE_INTEGER
,这个家伙的值是9007199254740991
。超过这个范围,你就得小心了,精度可能会丢失,导致一些奇奇怪怪的错误,比如:
console.log(Number.MAX_SAFE_INTEGER + 1); // 9007199254740992
console.log(Number.MAX_SAFE_INTEGER + 2); // 9007199254740992 咦?怎么没变?
看到了吧?加1还正常,加2就直接原地踏步了。这对于一些需要高精度计算的场景来说,简直就是噩梦。想象一下,你要计算银行利息,结果因为精度问题,少算了客户几块钱,那不得被投诉死?
BigInt
就是为了解决这个问题而生的。它是一种新的数据类型,可以表示任意精度的整数,再也不用担心数字太大导致精度丢失了。
怎么用呢?很简单,直接在数字后面加个n
就行了。
const bigNumber = 9007199254740991n;
console.log(bigNumber + 1n); // 9007199254740992n 这回没问题了吧!
或者,你也可以使用BigInt()
构造函数来创建BigInt
:
const anotherBigNumber = BigInt("9007199254740991");
console.log(anotherBigNumber + 1n); // 9007199254740992n
注意: BigInt
只能和BigInt
进行运算,不能和普通的Number
直接混用。如果你想和Number
运算,需要先将Number
转换为BigInt
,或者将BigInt
转换为Number
(但是要注意精度丢失的风险)。
const number = 10;
const bigNumber = 20n;
// console.log(number + bigNumber); // 报错:TypeError: Cannot mix BigInt and other types
console.log(BigInt(number) + bigNumber); // 30n
// 小心!可能会丢失精度
console.log(Number(bigNumber) + number); // 30
第二部分:BigInt
的常见用法
BigInt
支持常见的算术运算,比如加减乘除、取模等等。但是需要注意的是,除法运算会向下取整,也就是舍弃小数部分。
const a = 10n;
const b = 3n;
console.log(a + b); // 13n
console.log(a - b); // 7n
console.log(a * b); // 30n
console.log(a / b); // 3n 注意:向下取整了
console.log(a % b); // 1n
console.log(a ** b); // 1000n
BigInt
还支持位运算,比如与、或、异或、左移、右移等等。
const a = 10n; // 二进制:1010
const b = 3n; // 二进制:0011
console.log(a & b); // 2n (1010 & 0011 = 0010)
console.log(a | b); // 11n (1010 | 0011 = 1011)
console.log(a ^ b); // 9n (1010 ^ 0011 = 1001)
console.log(a << b); // 80n (1010 << 3 = 1010000)
console.log(a >> b); // 1n (1010 >> 3 = 0001)
BigInt
也可以进行比较运算,比如大于、小于、等于等等。
const a = 10n;
const b = 20n;
console.log(a > b); // false
console.log(a < b); // true
console.log(a == b); // false
console.log(a != b); // true
console.log(a >= b); // false
console.log(a <= b); // true
第三部分:BigInt
的浏览器兼容性
虽然BigInt
很强大,但是并不是所有的浏览器都支持它。一些老旧的浏览器,比如IE,可能根本就不认识BigInt
。
这时候,我们就需要用到polyfill
了。polyfill
是一种代码,它可以让老浏览器也能支持新的JavaScript特性。
第四部分:BigInt
的 polyfill
实现
polyfill
的核心思想是,如果浏览器不支持 BigInt
,我们就用 JavaScript 代码来模拟 BigInt
的行为。
一种常见的 BigInt
polyfill
实现方式是使用数组来存储大数的每一位。例如,数字 12345678901234567890
可以存储为 [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
。
接下来,我们需要实现 BigInt
的各种运算,例如加法、减法、乘法、除法等等。这些运算都需要手动模拟,因为 JavaScript 内置的数字类型无法处理这么大的数字。
下面是一个简单的 BigInt
polyfill
的示例代码,只实现了加法运算。
// 简易版 BigInt Polyfill
(function() {
if (typeof BigInt !== 'undefined') {
return; // 如果浏览器已经支持 BigInt,则直接返回
}
function FakeBigInt(value) {
if (typeof value === 'number') {
this.digits = String(value).split('').map(Number);
} else if (typeof value === 'string') {
this.digits = value.split('').map(Number);
} else if (value instanceof FakeBigInt) {
this.digits = value.digits.slice(); // 复制数组
} else {
throw new TypeError('Invalid argument for FakeBigInt');
}
}
FakeBigInt.prototype.toString = function() {
return this.digits.join('');
};
function add(a, b) {
a = new FakeBigInt(a);
b = new FakeBigInt(b);
let result = [];
let carry = 0;
let i = a.digits.length - 1;
let j = b.digits.length - 1;
while (i >= 0 || j >= 0 || carry) {
const digitA = i >= 0 ? a.digits[i] : 0;
const digitB = j >= 0 ? b.digits[j] : 0;
const sum = digitA + digitB + carry;
const digit = sum % 10;
carry = Math.floor(sum / 10);
result.unshift(digit);
i--;
j--;
}
return new FakeBigInt(result.join(''));
}
window.FakeBigInt = FakeBigInt;
window.addBigInt = add; // 暴露加法函数
})();
// 使用示例
let a = new FakeBigInt("12345678901234567890");
let b = new FakeBigInt("98765432109876543210");
let sum = addBigInt(a, b);
console.log(sum.toString()); // 输出 "111111111011111111100"
代码解释:
-
检查原生支持: 首先,我们检查浏览器是否已经支持
BigInt
。如果支持,就直接返回,不需要polyfill
。 -
FakeBigInt
构造函数: 这个构造函数用于创建一个FakeBigInt
对象。它可以接受一个数字、一个字符串或者另一个FakeBigInt
对象作为参数。它将数字或字符串转换为一个数字数组,并存储在this.digits
属性中。 -
toString
方法: 这个方法用于将FakeBigInt
对象转换为字符串。它将this.digits
数组中的数字连接起来,并返回结果。 -
add
函数: 这个函数用于计算两个FakeBigInt
对象的和。它首先将两个参数转换为FakeBigInt
对象,然后创建一个空数组result
用于存储结果。接下来,它从两个数组的末尾开始,逐位计算和,并处理进位。最后,它将结果数组转换为一个FakeBigInt
对象,并返回。 -
暴露
FakeBigInt
和addBigInt
: 我们将FakeBigInt
构造函数和add
函数暴露给全局作用域,以便可以在其他地方使用它们。
这个 polyfill
非常简陋,只实现了加法运算,而且没有进行任何优化。但是,它可以帮助你理解 BigInt
polyfill
的基本原理。
更完善的 polyfill
方案:
上面的代码只是一个示例,实际的 BigInt
polyfill
需要实现更多的运算,并且需要进行优化,以提高性能。
目前比较流行的 BigInt
polyfill
库有:
big-integer
: 一个功能完善、性能优异的BigInt
库。它提供了各种算术运算、位运算、比较运算等等,并且经过了大量的优化。jsbi
: 由 Google 开发的BigInt
polyfill
。它旨在提供与原生BigInt
尽可能接近的性能。
使用这些库非常简单,只需要将它们引入到你的项目中,然后就可以像使用原生 BigInt
一样使用它们了。
例如,使用 big-integer
:
<script src="big-integer.js"></script>
<script>
let a = bigInt("12345678901234567890");
let b = bigInt("98765432109876543210");
let sum = a.add(b);
console.log(sum.toString()); // 输出 "111111111011111111100"
</script>
第五部分:性能考量
虽然 polyfill
能够解决兼容性问题,但它也带来了一些性能上的损失。毕竟,用 JavaScript 模拟 BigInt
的行为,肯定没有原生 BigInt
快。
因此,在使用 BigInt
polyfill
时,需要权衡兼容性和性能。如果你的应用对性能要求很高,那么最好尽量使用支持原生 BigInt
的浏览器。如果你的应用需要兼容老旧的浏览器,那么可以使用 polyfill
,但要注意避免在大规模计算中使用 BigInt
,以免影响性能。
第六部分:BigInt
的应用场景
BigInt
在很多场景下都有用武之地,比如:
- 密码学: 密码学中经常需要进行大数运算,比如 RSA 算法。
BigInt
可以方便地处理这些大数,而不用担心精度丢失。 - 金融计算: 金融计算对精度要求非常高。
BigInt
可以保证计算结果的准确性,避免出现财务上的损失。 - 科学计算: 科学计算中也经常需要进行大数运算,比如计算天文数字、物理常数等等。
BigInt
可以方便地处理这些大数,而不用自己实现大数运算的算法。 - 游戏开发: 在一些游戏中,可能需要处理非常大的数值,比如玩家的经验值、金币数量等等。
BigInt
可以保证这些数值的准确性,避免出现溢出问题。
第七部分:Number
vs BigInt
对比表格
特性 | Number |
BigInt |
---|---|---|
数据类型 | 浮点数 (双精度 64 位二进制格式) | 任意精度的整数 |
安全整数范围 | -2^53 到 2^53 ( Number.MAX_SAFE_INTEGER ) |
没有限制 |
字面量表示 | 无后缀 | 后缀 n |
运算 | 内置算术运算符 | 需注意类型转换,不能直接与 Number 运算 |
精度 | 精度可能丢失,尤其是在超出安全整数范围时 | 精度保证 |
浏览器兼容性 | 广泛支持 | 部分老旧浏览器不支持,需要 polyfill |
使用场景 | 常规数值计算 | 需要高精度的大数运算 |
第八部分:总结
今天我们一起学习了 BigInt
的基本概念、常见用法、浏览器兼容性以及 polyfill
的实现方式。希望大家对 BigInt
有了更深入的了解。
BigInt
是一种非常有用的数据类型,可以解决 JavaScript 中大数运算的精度问题。虽然它有一些局限性,比如不能直接与 Number
混用,以及在老旧浏览器中需要 polyfill
,但它仍然是 JavaScript 开发者工具箱中一个重要的工具。
记住,选择合适的工具,才能更好地解决问题。在需要高精度计算的场景下,BigInt
绝对是你的不二之选。
好了,今天的讲座就到这里。谢谢大家!如果有什么问题,欢迎随时提问。