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