json-bigint的介绍和使用-解决Javascript的有关大整数问题
JavaScript 能够准确表示的整数范围在-2^53到 2^53之间(不含两个端点),超过这个范围,无法精确表示这个值,这使得 JavaScript 不适合进行科学和金融方面的精确计算。
先举个例子
Math.pow(2, 53) // 9007199254740992 9007199254740992 // 9007199254740992 9007199254740993 // 9007199254740992 Math.pow(2, 53) === Math.pow(2, 53) + 1 // true
上面代码中,超出 2 的 53 次方之后,一个数就不精确了。
ES6 引入了Number.MAX_SAFE_INTEGER和Number.MIN_SAFE_INTEGER这两个常量,用来表示这个范围的上下限。
Number.MAX_SAFE_INTEGER === Math.pow(2, 53) - 1 // true Number.MAX_SAFE_INTEGER === 9007199254740991 // true Number.MIN_SAFE_INTEGER === -Number.MAX_SAFE_INTEGER // true Number.MIN_SAFE_INTEGER === -9007199254740991 // true
上面代码中,可以看到 JavaScript 能够精确表示的极限。
后端返回的数据一般都是 JSON 格式的字符串。
'{ "id": 9007199254740995, "name": "Jack", "age": 18 }'
如果这个字符不做任何处理,你能方便的获取到字符串中的指定数据吗?非常麻烦。所以我们要把它转换为 JavaScript 对象来使用就很方便了。
幸运的是 axios 为了方便我们使用数据,它会在内部使用 JSON.parse() 把后端返回的数据转为 JavaScript 对象。
// { id: 9007199254740996, name: 'Jack', age: 18 } JSON.parse('{ "id": 9007199254740995, "name": "Jack", "age": 18 }')
可以看到,超出安全整数范围的 id 无法精确表示,这个问题并不是 axios 的错。
了解了什么是大整数的概念,接下来的问题是如何解决?
json-bigint 是一个第三方包,它可以帮我们很好的处理这个问题。
使用它的第一步就是把它安装到你的项目中。
npm i json-bigint
下面是使用它的一个简单示例。
const jsonStr = '{ "art_id": 1245953273786007552 }' console.log(JSON.parse(jsonStr)) // 1245953273786007600 // JSON.stringify() // JSONBig 可以处理数据中超出 JavaScript 安全整数范围的问题 console.log(JSONBig.parse(jsonStr)) // 把 JSON 格式的字符串转为 JavaScript 对象 // 使用的时候需要把 BigNumber 类型的数据转为字符串来使用 console.log(JSONBig.parse(jsonStr).art_id.toString()) // 1245953273786007552 console.log(JSON.stringify(JSONBig.parse(jsonStr))) console.log(JSONBig.stringify(JSONBig.parse(jsonStr))) // 把 JavaScript 对象 转为 JSON 格式的字符串转
json-bigint 会把超出 JS 安全整数范围的数字转为一个 BigNumber 类型的对象,对象数据是它内部的一个算法处理之后的,我们要做的就是在使用的时候转为字符串来使用。
解决方法:(案例)
通过 Axios 请求得到的数据都是 Axios 处理(JSON.parse)之后的,我们应该在 Axios 执行处理之前手动使用 json-bigint 来解析处理。Axios 提供了自定义处理原始后端返回数据的 API:transformResponse 。
import axios from 'axios' import jsonBig from 'json-bigint' var json = '{ "value" : 9223372036854775807, "v2": 123 }' console.log(jsonBig.parse(json)) const request = axios.create({ baseURL: '你接口的基础路径', // 接口基础路径 // transformResponse 允许自定义原始的响应数据(字符串) transformResponse: [function (data) { try { // 如果转换成功则返回转换的数据结果 return jsonBig.parse(data) } catch (err) { // 如果转换失败,则包装为统一数据格式并返回 return { data } } }] }) export default request
更多内容请参见:
https://www.teqng.com/2021/07/29/node-js-%E4%B8%AD%E9%81%87%E5%88%B0%E5%A4%A7%E6%95%B0%E5%A4%84%E7%90%86%E7%B2%BE%E5%BA%A6%E4%B8%A2%E5%A4%B1%E5%A6%82%E4%BD%95%E8%A7%A3%E5%86%B3%EF%BC%9F/#JavaScript_zui_da_an_quan_zheng_shu