我正在参与掘金创作者训练营第4期,点击了解活动详情,一起学习吧!
最近项目联调时候遇到一个问题,前台请求不到数据,后台postman里面确实请求正常,真是太令人费解了。。。
参数发给后台让查找数据库,结果数据库中查找不到该参数。。。
多方排查后发现,接口在preview和response里面的数据竟然不一致!!!
priveiw数据
response数据
数据为
Long型
,返回给浏览器以后,浏览器转换数据格式的时候出现问题。JS在处理返回数据类型是Long的时候,Long类型位数过长(js里面number类型的数值范围是2的53次方减1,即9007199254740991
),精度会丢失一部分。
后来反应过来又去看response的数据发现这里返回的数据是正常的,preview是丢失后的数据
。
解决
只要服务端把数据转成string
就可以了
深入研究
Number
对象是采用64位存储的,即8个字节 * 8位 = 64位- 操作符在操作Number类型时,实际是操作的32位
- 在底层再把32位转换成64位进行处理
所以
- 最大的整数就是2的32次方减1
- 即
2 ** 32 - 1
- 数组索引时也能佐证,因为数组的索引是整数,最大的索引就是
2 ** 32 - 1
即4294967295
JAVA
侧返回的订单编号或用户ID都整型,在Web
侧会出现后面2位超出JavaScript
整数取值范围
如下:
java = 123456789012345678; // 一共18个数
js = 123456789012345600; // 一共16个数外加2个0
在新的ECMAScript
规范中也添加了1个Number常量最大安全整数Number.MAX_SAFE_INTEGER
- 这个里面的最大整数和上面的一样,是16个数
- 即2的53次方-1
2 ** 53 - 1
double 浮点数结构如下:
- 1 位符号位
- 11 位指数位
- 52 位尾数位
使用 52 位表示一个数的整数部分,那么最大可以精确表示的数应该是 2^52 - 1
才对, 就像 64 位表示整数时那样: 2^63 - 1
(去掉 1 位符号位)。 但其实浮点数在保存数字的时候做了规格化处理,以 10 进制为例:
**
20*10^2 => 2*10^3 //小数点前只需要保留 1 位数
对于二进制来说, 小数点前保留一位, 规格化后始终是 1.***
, 节省了 1 bit,这个 1 并不需要保存。
总结
出现上面原因还是因为后台的id超过了int的最大范围。但是记得最近JS出了bigInt类型来表示大整数,那是不是页能用bigInt来定义特别大的id呢?
BigInt
是一种内置对象,它提供了一种方法来表示大于 > 2^53 - 1
的整数。这原本是 Javascript中可以用 Number
表示的最大数字。BigInt
可以表示任意大的整数。
可以用在一个整数字面量后面加
n
的方式定义一个BigInt
,如:10n
,或者调用函数BigInt()
。
const theBiggestInt = 9007199254740991n;
const alsoHuge = BigInt(9007199254740991);
// ↪ 9007199254740991n
const hugeString = BigInt("9007199254740991");
// ↪ 9007199254740991n
const hugeHex = BigInt("0x1fffffffffffff");
// ↪ 9007199254740991n
const hugeBin = BigInt("0b11111111111111111111111111111111111111111111111111111");
// ↪ 9007199254740991n
它在某些方面类似于 Number
,但是也有几个关键的不同点:
- 不能用于
Math
对象中的方法; - 不能和任何
Number
实例混合运算,两者必须转换成同一种类型。在两种类型来回转换时要小心,因为BigInt
变量在转换成Number
变量时可能会丢失精度。