BigInt
数据类型的目标是比Number
数据类型反对的范畴更大的整数值。在对大整数执行数学运算时,以任意精度示意整数的能力尤为重要。应用BigInt
,整数溢出将不再是问题。
此外,能够平安地应用更加精确工夫戳,大整数ID等,而无需应用变通方法。 BigInt
目前是第3阶段提案, 一旦增加到标准中,它就是JS 第二个数字数据类型,也将是 JS 第8种根本数据类型:
- Boolean
- Null
- Undefined
- Number
- BigInt
- String
- Symbol
- Object
在本文中,咱们将具体介绍BigInt
,看看它如何解决应用Number
类型的限度。
问题
对于学过其余语言的程序员来说,JS中短少显式整数类型经常令人困惑。许多编程语言反对多种数字类型,如浮点型、双精度型、整数型和双精度型,但JS却不是这样。在JS中,依照IEEE 754-2008规范的定义,所有数字都以双精度64位浮点格局示意。
在此规范下,无奈准确示意的十分大的整数将主动四舍五入。确切地说,JS 中的Number
类型只能平安地示意-9007199254740991 (-(2^53-1))
和9007199254740991(2^53-1)
之间的整数,任何超出此范畴的整数值都可能失去精度。
console.log(9999999999999999); // → 10000000000000000
该整数大于JS Number 类型所能示意的最大整数,因而,它被四舍五入的。意外四舍五入会侵害程序的可靠性和安全性。这是另一个例子:
// 留神最初一位的数字9007199254740992 === 9007199254740993; // → true
JS 提供Number.MAX_SAFE_INTEGER
常量来示意 最大平安整数,Number.MIN_SAFE_INTEGER
常量示意最小平安整数:
const minInt = Number.MIN_SAFE_INTEGER;console.log(minInt); // → -9007199254740991console.log(minInt - 5); // → -9007199254740996// notice how this outputs the same value as aboveconsole.log(minInt - 4); // → -9007199254740996
解决方案
为了解决这些限度,一些JS开发人员应用字符串类型示意大整数。 例如,Twitter API 在应用 JSON 进行响应时会向对象增加字符串版本的 ID。 此外,还开发了许多库,例如 bignumber.js,以便更容易地解决大整数。
应用BigInt,应用程序不再须要变通方法或库来平安地示意Number.MAX_SAFE_INTEGER
和Number.Min_SAFE_INTEGER
之外的整数。 当初能够在规范JS中执行对大整数的算术运算,而不会有精度损失的危险。
要创立BigInt
,只需在整数的开端追加n即可。比拟:
console.log(9007199254740995n); // → 9007199254740995nconsole.log(9007199254740995); // → 9007199254740996
或者,能够调用BigInt()
构造函数
BigInt("9007199254740995"); // → 9007199254740995n
BigInt
文字也能够用二进制、八进制或十六进制示意
// binaryconsole.log(0b100000000000000000000000000000000000000000000000000011n);// → 9007199254740995n// hexconsole.log(0x20000000000003n);// → 9007199254740995n// octalconsole.log(0o400000000000000003n);// → 9007199254740995n// note that legacy octal syntax is not supportedconsole.log(0400000000000000003n);// → SyntaxError
请记住,不能应用严格相等运算符将BigInt
与惯例数字进行比拟,因为它们的类型不同:
console.log(10n === 10); // → falseconsole.log(typeof 10n); // → bigintconsole.log(typeof 10); // → number
相同,能够应用等号运算符,它在解决操作数之前执行隐式类型转换
console.log(10n == 10); // → true
除一元加号(+
)运算符外,所有算术运算符都可用于BigInt
10n + 20n; // → 30n10n - 20n; // → -10n+10n; // → TypeError: Cannot convert a BigInt value to a number-10n; // → -10n10n * 20n; // → 200n20n / 10n; // → 2n23n % 10n; // → 3n10n ** 3n; // → 1000nconst x = 10n;++x; // → 11n--x; // → 9n
不反对一元加号(+
)运算符的起因是某些程序可能依赖于+
始终生成Number
的不变量,或者抛出异样。 更改+
的行为也会毁坏asm.js
代码。
当然,与BigInt
操作数一起应用时,算术运算符应该返回BigInt
值。因而,除法(/
)运算符的后果会主动向下舍入到最靠近的整数。例如:
25 / 10; // → 2.525n / 10n; // → 2n
隐式类型转换
因为隐式类型转换可能失落信息,所以不容许在bigint
和 Number
之间进行混合操作。当混合应用大整数和浮点数时,后果值可能无奈由BigInt
或Number
准确示意。思考上面的例子:
(9007199254740992n + 1n) + 0.5
这个表达式的后果超出了BigInt
和Number
的范畴。小数局部的Number
不能准确地转换为BigInt
。大于2^53
的BigInt
不能精确地转换为数字。
因为这个限度,不可能对混合应用Number
和BigInt
操作数执行算术操作。还不能将BigInt
传递给Web api和内置的 JS 函数,这些函数须要一个 Number
类型的数字。尝试这样做会报TypeError
谬误
10 + 10n; // → TypeErrorMath.max(2n, 4n, 6n); // → TypeError
请留神,关系运算符不遵循此规定,如下例所示:
10n > 5; // → true
如果心愿应用BigInt
和Number
执行算术计算,首先须要确定应该在哪个类型中执行该操作。为此,只需通过调用Number()
或BigInt()
来转换操作数:
BigInt(10) + 10n; // → 20n// or10 + Number(10n); // → 20
当 Boolean
类型与BigInt
类型相遇时,BigInt
的解决形式与Number
相似,换句话说,只有不是0n
,BigInt
就被视为truthy
的值:
if (5n) { // 这里代码块将被执行}if (0n) { // 这里代码块不会执行}
排序BigInts
和Numbers
数组时,不会产生隐式类型转换:
const arr = [3n, 4, 2, 1n, 0, -1n];arr.sort(); // → [-1n, 0, 1n, 2, 3n, 4]
位操作符如|、&、<<、>>
和^
对Bigint
的操作形式与Number
相似。上面是一些例子
90 | 115; // → 12390n | 115n; // → 123n90n | 115; // → TypeError
BigInt构造函数
与其余根本类型一样,能够应用构造函数创立BigInt
。传递给BigInt()
的参数将主动转换为BigInt
:
BigInt("10"); // → 10nBigInt(10); // → 10nBigInt(true); // → 1n
无奈转换的数据类型和值会引发异样:
BigInt(10.2); // → RangeErrorBigInt(null); // → TypeErrorBigInt("abc"); // → SyntaxError
能够间接对应用构造函数创立的BigInt
执行算术操作
BigInt(10) * 10n; // → 100n
应用严格相等运算符的操作数时,应用构造函数创立的Bigint
与惯例Bigint
的解决形式相似
BigInt(true) === 1n; // → true
库函数
在撰写本文时,Chrome +67
和Opera +54
齐全反对BigInt
数据类型。可怜的是,Edge
和Safari
还没有实现它。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,等等,而不须要应用库。
重要的是要记住,不能应用Number
和BigInt
操作数的混合执行算术运算,须要通过显式转换其中的一种类型。 此外,出于兼容性起因,不容许在BigInt
上应用一元加号(+
)运算符。