讲讲笔者踩过的坑
为啥打印出来的数字和真实的数字不一样?
某次后端同学返回了一个极大的数字类型id,我们发现每次使用该id进行操作时,总是会不正确。于是和后端同学核对之后发现,前端显示的值,和后端真实返回的值并不一致。
当时笔者的心情是这样的
这种情况,大家也可以在浏览器的控制台复现一下,假设后端实际真实的值为:120000983300012345090,但是实际上浏览器内显示的值为:120000983300012340000
有经验的同学应该一下子就看出来端倪在哪:
由于JavaScript的数字为双精度IEEE 754 64位浮点类型,因此我们通过在控制台内使用Number.MAX_SAFE_INTEGER来查看最大安全整数如下:
现在我们可以看到,后端真实返回的值已经超过JavaScript的最大安全整数,因此JavaScript已经无法正确的处理这个数字了。
因此如果想要解决这个问题,请让后端同学给前端回传字符串类型的数字!!!
相等判断的坑 !!
现在让我们想一想,下面的运算结果应该是什么?~~
是不是有同学会认为这个结果是false?毕竟因为两个数字从数学意义上来说是不同的
120000983300012340000 === 120000983300012340001
但是实际上我们发现,这两个数字在JavaScript中判断是相等的
为什么会出现这个问题?
实际上就是我们刚刚所说的,由于数字超过了最大安全整数的范围,因此JavaScript无法精确的处理这些整数,导致了这些问题。
JavaScript中,也提供了Number.isSafeInteger()方法来检测数字是否在安全整数,当发现不是安全整数时,请小心操作该数字!!!
那么当数字超过最大安全整数时,有什么办法么?答案是:有!JavaScript内置了一个新的BigInt的类型
说说BigInt类型
创建一个BigInt数字
首先大家最关心的应该是我们怎么创建一个BigInt,接下来我们就来创建一个BigInt的数字
let bigIntNumber1 = 120000983300012340000n
let bigIntNumber2 = BigInt(120000983300012340000)
let bigIntNumber3 = BigInt('120000983300012340000')
可以看到,我们可以用数字后面尾缀n的方式来定义一个BigInt类型,也可以使用BigInt函数来定义。
**请注意,BigInt类型不能使用Math对象中的方法,也不能合Number类型的数字进行运算,如果要进行运算,只能是转化成同一类型,但是BigInt类型转化成Number类型时,可能会丢失精度,就像之前例子中那样!! **
来看看刚刚比较的两个数字
刚刚我们例子中本不应该相等但是变的相等的两个数字:120000983300012340000、120000983300012340001,在这种情况下是不相等的
120000983300012340000n === 120000983300012340001n
运算结果如下:
现在浏览器输出的结果符合我们的预期!
BigInt类型的信息是什么?
如果我们使用typeof来查看一个BigInt会返回什么结果呢?
typeof 1n
typeof 1n === 'bigint'
typeof BigInt('1') === 'bigint'
下面我们来看下浏览器中的运行结果
BigInt支持什么常见的运算?
BigInt支持使用下面常用的运算操作符,同时也支持除了>>>(无符号位移)外的位运算(因为BigInt是有符号的)
- + 加法
- * 乘法
- - 减法
- ** n次方
- % 取余
在使用除法时,需要注意,一旦除后出现小数,会向零取整,参考下面的例子
11n / 5n
11n / 3n
10n / 5n
下面是浏览器中的运算结果
请注意!我们经常使用+将一个值转化为Number类型,但是BigInt中为了避免混淆,因此不支持一元加法运算符!,请使用Number()方法将BigInt类型转化为Number类型!
let bigint = 1n;
+bigint
Number(bigint)
BigInt如何与Number进行比较?
BigInt与Number,不能严格相等,但是可以宽松相等
0n === 0
0n == 0
下面是浏览器的运算结果:
BigInt可以正常的与Number进行比较
2n > 1n
2n > 1
我们看到,浏览器运算的结果均为我们的预期值
BigInt如何进行布尔运算?
在if或者其它的布尔运算中,BigInt类型和Number类型类似,0n会被认为是false
接下来让我们想一下,下面的运算结果究竟是什么:
if (0n) {
console.log('执行了if!');
} else {
console.log('执行了else!');
}
0n || 12n
0n && 12n
Boolean(0n)
Boolean(12n)
!12n
!0n
揭晓一下我们在浏览器内运行的结果:
看看BigInt的兼容性
目前BigInt的兼容性不太好,只有Chrome和Firefox较新版本的浏览器才能支持,Safari系全部沦陷,因此请谨慎使用,更多信息请参照:caniuse.com/#feat=bigin…
写在最后
虽然BigInt目前浏览器支持不佳,但是不妨碍我们了解这个基本的数据类型~~在平时写业务的过程中,也要提醒后端同学注意给前端回传超过安全整数的数字!!