前言

前端的同学基本都遇到过,关于在前端中使用大数据导致js精度丢失的问题;
比如:
后端给前端返回一个数字类型的id,
但是,
前端对这个id不做任何处理,直接使用到下一个给后端请求的时候,
接口报错了,
后端一查,说,你前端id给传错了,然后前端一看,果然是给传错了,
但是自己又没有做什么,怎么拿的就怎么给后端了。问题出在哪呢?
最后,才知道是因为 :
后端给的数字太大超过-9007199254740991 (-(2^53-1))9007199254740991(2^53-1)之间的整数,前端js这块就会自动四舍五入,导致精度丢失

image.png

再比如: 前端要进行大数字之间的运算,也会精度丢失。

可转成字符串

让后端把传过来的id转成字符串
我司后端当时说他转成字符串了,
但是我这边拿着热乎的数据,检测了类型,是数字非字符串,当然精度依旧会丢失。
最后,
我让他直接简单粗暴加个双引号,我这边检测类型才是字符串,
也不知道为啥,是后端转的有问题还是什么原因。
当然,拿到字符串的id,再传给后端是没有问题的,精度就不会丢失

问题

前端大数字之间的运算,精度丢失问题无法解决;

BigInt

因为number的基本类型不能超过2^53,不然就会精度丢失
为了解决这个限制,在ECMAScript标准中出现了BigInt

什么是?

BigInt可以表示任意大的整数;

创建

  1. 直接BigInt去创建;
    BigInt(value)

  1. 后面加个n就可

当然,此方式可以成功解决前端大数字之间运算的问题;

前端直接把热乎的id转成字符串也会精度丢失,但配合BigInt解决了此问题

有次,我是拿到后端给的number类型的id,明明拿着热乎的数据,直接String,转成字符串时,就已经精度丢失了;
于是,我用了第一种方式,让后端给我传过来时,就加双引号转成字符;
第二种方式就是我这边用了BigInt, 本来我以为我这边拿着热乎的id直接Sting一下, 然后传给后端,发现不行,精度也是丢失了,于是就这样:

String(BigInt(result));
String配合BigInt,
就可以,解决精度丢失并顺利转成字符传给后端的问题;

结尾

上面,是我的项目中遇到跟后端合作时,前端大数据精度丢失的问题;
我是把后端Number类型的id通过String和BigInt转成字符串传给后端;
但是,咱们就技术而言,不论其他:(平常肯定都是推给后端,让后端转去),
如果后端要求给他传过去的id类型是Number呢,各位大佬可否知道,前端有没有什么好的方式解决呢?

注意:(ps: 因评论区有几个掘友这里有疑问,这里就补写一下)

前端直接这样写大数据转换不行:


let result=124569875984123677888999;  //估摸着这一步就在前端已经精度丢失了
String(BigInt(result));

let result=124569875984123677888999;这一步精度就可能已经丢失了;

下面这种也不行

let result=BigInt(124569875984123677888999);   //这里也已经精度丢失了
String(result);


因为在这一步,BigInt(124569875984123677888999)
你还没来的及转成BigInt,就已经精度丢失了;

下面这样就可以;
前端的大数据,可以在第一步就先给大数据后加n,直接写成BigInt类型的就可以;

let result=124569875984123677888999n; 
String(result);


因为你一开始在前端写的数据就是BigInt类型的,所以不会造成精度丢失问题;

文章上面我是直接拿后端返过来的number类型的大数据,然后直接String(BigInt(result))这样子再传给后端是可以的。
前端直接那样写的number类型大数据的话,一开始就可能会造成丢失精度,
除非可在前端大数据后面直接加n的方式,一开始就写成BigInt类型的也是可以的。