你真的了解BigInt吗?

587 阅读3分钟

BigInt

BigInt 是一种数字类型的数据,它可以表示任意精度格式的整数。而在其他编程语言中,可以存在不同的数字类型,例如:整数、浮点数、双精度数或大斐波数。

JavaScript 所有数字都保存成 64 位浮点数,这给数值的表示带来了两大限制。一是数值的精度只能到 53 个二进制位(相当于 16 个十进制位),大于这个范围的整数,JavaScript 是无法精确表示的,这使得 JavaScript 不适合进行科学和金融方面的精确计算。二是大于或等于2的1024次方的数值,JavaScript 无法表示,会返回Infinity。

// 超过 53 个二进制位的数值,无法保持精度
Math.pow(2, 53) === Math.pow(2, 53) + 1 // true
 
// 超过 2 的 1024 次方的数值,无法表示
Math.pow(2, 1024) // Infinity

ES6 引入了一种新的数据类型 BigInt,来解决这个问题。BigInt 只用来表示整数,没有位数的限制,任何位数的整数都可以精确表示。

const a = 217214165453453453n;
const b = 153463453453453349309n;

// BigInt 可以保持精度
a * b // 33334444555453453453543566667777n

// 普通整数无法保持精度
Number(a) * Number(b) // 3333444534535555453453453466670000

为了与 Number 类型进行区分,BigInt 类型的数据必须添加后缀n。

666 	// 普通Number
666n // BigInt
 
// BigInt 的运算
1n + 2n // 3n

BigInt 同样可以使用各种进制表示,都要加上后缀n

0b1101n // 二进制
0o777n // 八进制

BigInt 可以使用负号(-),但是不能使用正号(+),因为会与 asm.js 冲突。

-2n // 正确
+2n // 报错

BigInt 函数

JavaScript 原生提供BigInt函数,可以用它生成 BigInt 类型的数值。转换规则基本与Number()一致,将其他类型的值转为 BigInt。

BigInt(1) // 1n
BigInt('1') // 1n
BigInt(false) // 0n
BigInt(true) // 1n

注意:BigInt() 函数必须要有参数且不能接收undefined、null、'a'(字符串)、'1n'(BigInt类型的值)。且不能对BigInt() 函数使用new关键字。new BigInt() // TypeError,参数如果是小数,也会报错BigInt(1.5) // RangeError

BigIn的运算

在运算方面,BigInt 类型的+-***,与 Number 类型的行为一致。除法运算/会舍去小数部分,返回一个整数。

12n / 5n
// 2n

注意:

  • 不带符号的右移位运算符>>>
  • 一元的求正运算符+ 上面两个运算符用在 BigInt 会报错。前者是因为>>>运算符是不带符号的,但是 BigInt 总是带有符号的,导致该运算无意义,完全等同于右移运算符>>。后者是因为一元运算符+在 asm.js标准规定里面总是返回 Number 类型,为了不破坏 asm.js 就规定+1n会报错。

BigInt 不能与普通数值进行混合运算。

1n + 1 // 报错

上面代码报错是因为无论返回的是 BigInt 或 Number,都会导致丢失精度信息。比如(1n**1n + 1n) + 0.5这个表达式,如果返回 BigInt 类型,0.5这个小数部分会丢失;如果返回 Number 类型,有效精度只能保持 53 位,导致精度下降。

同样的原因,如果一个标准库函数的参数预期是 Number 类型,但是得到的是一个 BigInt,就会报错。

写在最后

伙伴们,如果你觉得我写的文章对你有帮助就给zayyo点一个赞👍或者关注➕都是对我最大的支持。当然你也可以加我微信:IsZhangjianhao,邀你进我的前端学习交流群,一起学习前端,成为更优秀的工程师~

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 18 天,点击查看活动详情