【JavaScript】Json.parse出现精度问题

856 阅读2分钟

问题背景

后端返回的数据是数组字符串,数组里的元素每个还是number类型,比如:a: "[1,2,79999999999999999]";

而前端需要的格式是数组,数组中的元素是字符串:a: ['1', '2', '79999999999999999'];

这两种格式正好相反,关键里面的元素是一个位数很多的id;

遇到问题

前端处理: 首先需要将字符串转成数组,执行JSON.parse(a), 输出: [1, 2, 80000000000000000]

此时,精度出现了问题,超过16位的数四舍五入了

原因

JavaScript中能精准表示的最大整数是 Math.pow(2, 53),数字太大就可能丢失精度,JS在处理比2^53大的数据时,精度会出现问题;

解决办法

  1. 后端修改返回数据:
  • 其实是后端传的数据格式不符合通用逻辑,一种是返回前端所需要的数据格式:a: ["1","2","79999999999999999"];
  • 如果非要传字符串,那就应该返回a: "1,2,79999999999999999",这样前端只需要a.split(',')就能解决, 不会引起精度问题;
  1. 前端通过正则匹配,给数组添加引号:

    如果后端死活不改的话,第二种解决办法就是通过正则,在JSON.parse()前先通过正则,给数组中元素加上引号,这样再执行JSON.parse时就不会出现精度问题了,具体方法见下面代码。

    const  a=   "[1,2,79999999999999999]"
    JSON.parse(a.replace(/(-?\d+)/g, '"$1"'))
    // 正负数都通用
    // 上面正则的意思找到数字,给数字添加双引号
    // 输出:  ['1', '2', '79999999999999999']

3. 使用bigint数据类型(本项目没使用):

BigInt 是一种内置对象,它提供了一种方法来表示大于 2^53 - 1 的整数。这原本是 Javascript 中可以用 Number 表示的最大数字。BigInt 可以表示任意大的整数。

但是请注意:

对任何 BigInt 值使用 JSON.stringify() 都会引发 TypeError,因为默认情况下 BigInt 值不会在 JSON 中序列化。但是,如果需要,可以实现 toJSON 方法: BigInt.prototype.toJSON = function() { return this.toString(); }

BigInt.prototype.toJSON = function() { return this.toString(); }