JS最新基本數據類型:BigInt

阿里雲最近在作活動,低至2折,有興趣能夠看看:
https://promotion.aliyun.com/...

爲了保證的可讀性,本文采用意譯而非直譯。javascript

BigInt數據類型的目的是比Number數據類型支持的範圍更大的整數值。在對大整數執行數學運算時,以任意精度表示整數的能力尤其重要。使用BigInt,整數溢出將再也不是問題。html

此外,能夠安全地使用更加準確時間戳,大整數ID等,而無需使用變通方法。 BigInt目前是第3階段提案, 一旦添加到規範中,它就是JS 第二個數字數據類型,也將是 JS 第8種基本數據類型:前端

  • Boolean
  • Null
  • Undefined
  • Number
  • BigInt
  • String
  • Symbol
  • Object

在本文中,我們將詳細介紹BigInt,看看它如何解決使用Number類型的限制。java

問題

對於學過其餘語言的程序員來講,JS中缺乏顯式整數類型經常使人困惑。許多編程語言支持多種數字類型,如浮點型、雙精度型、整數型和雙精度型,但JS卻不是這樣。在JS中,按照IEEE 754-2008標準的定義,全部數字都以雙精度64位浮點格式表示。git

在此標準下,沒法精確表示的很是大的整數將自動四捨五入。確切地說,JS 中的Number類型只能安全地表示-9007199254740991 (-(2^53-1))9007199254740991(2^53-1)之間的整數,任何超出此範圍的整數值均可能失去精度。程序員

console.log(9999999999999999);    // → 10000000000000000

該整數大於JS Number 類型所能表示的最大整數,所以,它被四捨五入的。意外四捨五入會損害程序的可靠性和安全性。這是另外一個例子:github

// 注意最後一位的數字
9007199254740992 === 9007199254740993;    // → true

JS 提供Number.MAX_SAFE_INTEGER常量來表示 最大安全整數,Number.MIN_SAFE_INTEGER常量表示最小安全整數:編程

const minInt = Number.MIN_SAFE_INTEGER;

console.log(minInt);         // → -9007199254740991

console.log(minInt - 5);     // → -9007199254740996

// notice how this outputs the same value as above
console.log(minInt - 4);     // → -9007199254740996

解決方案

爲了解決這些限制,一些JS開發人員使用字符串類型表示大整數。 例如,Twitter API 在使用 JSON 進行響應時會向對象添加字符串版本的 ID。 此外,還開發了許多庫,例如 bignumber.js,以便更容易地處理大整數。api

使用BigInt,應用程序再也不須要變通方法或庫來安全地表示Number.MAX_SAFE_INTEGERNumber.Min_SAFE_INTEGER以外的整數。 如今能夠在標準JS中執行對大整數的算術運算,而不會有精度損失的風險。數組

要建立BigInt,只需在整數的末尾追加n便可。比較:

console.log(9007199254740995n);    // → 9007199254740995n
console.log(9007199254740995);     // → 9007199254740996

或者,能夠調用BigInt()構造函數

BigInt("9007199254740995");    // → 9007199254740995n

BigInt文字也能夠用二進制、八進制或十六進制表示

// binary
console.log(0b100000000000000000000000000000000000000000000000000011n);
// → 9007199254740995n

// hex
console.log(0x20000000000003n);
// → 9007199254740995n

// octal
console.log(0o400000000000000003n);
// → 9007199254740995n

// note that legacy octal syntax is not supported
console.log(0400000000000000003n);
// → SyntaxError

請記住,不能使用嚴格相等運算符將BigInt與常規數字進行比較,由於它們的類型不一樣:

console.log(10n === 10);    // → false

console.log(typeof 10n);    // → bigint
console.log(typeof 10);     // → number

相反,可使用等號運算符,它在處理操做數以前執行隱式類型轉換

console.log(10n == 10);    // → true

除一元加號(+)運算符外,全部算術運算符均可用於BigInt

10n + 20n;    // → 30n
10n - 20n;    // → -10n
+10n;         // → TypeError: Cannot convert a BigInt value to a number
-10n;         // → -10n
10n * 20n;    // → 200n
20n / 10n;    // → 2n
23n % 10n;    // → 3n
10n ** 3n;    // → 1000n

const x = 10n;
++x;          // → 11n
--x;          // → 9n

不支持一元加號(+)運算符的緣由是某些程序可能依賴於+始終生成Number的不變量,或者拋出異常。 更改+的行爲也會破壞asm.js代碼。

固然,與BigInt操做數一塊兒使用時,算術運算符應該返回BigInt值。所以,除法(/)運算符的結果會自動向下舍入到最接近的整數。例如:

25 / 10;      // → 2.5
25n / 10n;    // → 2n

隱式類型轉換

由於隱式類型轉換可能丟失信息,因此不容許在bigintNumber 之間進行混合操做。當混合使用大整數和浮點數時,結果值可能沒法由BigIntNumber精確表示。思考下面的例子:

(9007199254740992n + 1n) + 0.5

這個表達式的結果超出了BigIntNumber的範圍。小數部分的Number不能精確地轉換爲BigInt。大於2^53BigInt不能準確地轉換爲數字。

因爲這個限制,不可能對混合使用NumberBigInt操做數執行算術操做。還不能將BigInt傳遞給Web api和內置的 JS 函數,這些函數須要一個 Number 類型的數字。嘗試這樣作會報TypeError錯誤

10 + 10n;    // → TypeError
Math.max(2n, 4n, 6n);    // → TypeError

請注意,關係運算符不遵循此規則,以下例所示:

10n > 5;    // → true

若是但願使用BigIntNumber執行算術計算,首先須要肯定應該在哪一個類型中執行該操做。爲此,只需經過調用Number()BigInt()來轉換操做數:

BigInt(10) + 10n;    // → 20n
// or
10 + Number(10n);    // → 20

Boolean 類型與BigInt 類型相遇時,BigInt的處理方式與Number相似,換句話說,只要不是0nBigInt就被視爲truthy的值:

if (5n) {
    // 這裏代碼塊將被執行
}

if (0n) {
    // 這裏代碼塊不會執行
}

排序BigIntsNumbers數組時,不會發生隱式類型轉換:

const arr = [3n, 4, 2, 1n, 0, -1n];

arr.sort();    // → [-1n, 0, 1n, 2, 3n, 4]

位操做符如|、&、<<、>>^Bigint的操做方式與Number相似。下面是一些例子

90 | 115;      // → 123
90n | 115n;    // → 123n
90n | 115;     // → TypeError

BigInt構造函數

與其餘基本類型同樣,可使用構造函數建立BigInt。傳遞給BigInt()的參數將自動轉換爲BigInt:

BigInt("10");    // → 10n
BigInt(10);      // → 10n
BigInt(true);    // → 1n

沒法轉換的數據類型和值會引起異常:

BigInt(10.2);     // → RangeError
BigInt(null);     // → TypeError
BigInt("abc");    // → SyntaxError

能夠直接對使用構造函數建立的BigInt執行算術操做

BigInt(10) * 10n;    // → 100n

使用嚴格相等運算符的操做數時,使用構造函數建立的Bigint與常規Bigint的處理方式相似

BigInt(true) === 1n;    // → true

庫函數

在撰寫本文時,Chrome +67Opera +54徹底支持BigInt數據類型。不幸的是,EdgeSafari尚未實現它。Firefox默認不支持BigInt,可是能夠在about:config中將javascript.options.bigint 設置爲true來開啓它,最新支持的狀況可在「Can I use」上查看。

不幸的是,轉換BigInt是一個極其複雜的過程,這會致使嚴重的運行時性能損失。直接polyfill BigInt也是不可能的,由於該提議改變了幾個現有操做符的行爲。目前,更好的選擇是使用JSBI庫,它是BigInt提案的純JS實現。

這個庫提供了一個與原生BigInt行爲徹底相同的API。下面是如何使用JSBI:

import JSBI from './jsbi.mjs';

const b1 = JSBI.BigInt(Number.MAX_SAFE_INTEGER);
const b2 = JSBI.BigInt('10');

const result = JSBI.add(b1, b2);

console.log(String(result));    // → '9007199254741001'

使用JSBI的一個優勢是,一旦瀏覽器支持,就不須要重寫代碼。 相反,可使用babel插件自動將JSBI代碼編譯爲原生 BigInt代碼。

總結

BigInt是一種新的數據類型,用於當整數值大於Number數據類型支持的範圍時。這種數據類型容許咱們安全地對大整數執行算術操做,表示高分辨率的時間戳,使用大整數id,等等,而不須要使用庫。

重要的是要記住,不能使用NumberBigInt操做數的混合執行算術運算,須要經過顯式轉換其中的一種類型。 此外,出於兼容性緣由,不容許在BigInt上使用一元加號(+)運算符。

交流

乾貨系列文章彙總以下,以爲不錯點個Star,歡迎 加羣 互相學習。

https://github.com/qq44924588...

我是小智,公衆號「大遷世界」做者,對前端技術保持學習愛好者。我會常常分享本身所學所看的乾貨,在進階的路上,共勉!

關注公衆號,後臺回覆福利,便可看到福利,你懂的。

clipboard.png

相關文章
相關標籤/搜索