【笔记】第七种基本数据类型BigInt
Nov 11, 2019笔记jses6
第七种基本数据类型BigInt
js 采用双精度浮点数,这也导致了精度有限的问题。在 js 中,Number 基本类型可以精确表示的最大整数是 2^53
。因此早期会有这如下的“bug”:
1 | let max = Number.MAX_SAFE_INTEGER; // 最大安全整数 |
为了解决这个限制,BigInt出现在了ECMAScript标准中。1
2
3
4
5
6let max = BigInt(Number.MAX_SAFE_INTEGER);
let max1 = max + 1n
let max2 = max + 2n
max1 === max2 // false
介绍
BigInt 可以表示任意大的整数。
创建
语法:1
BigInt(value);
其中参数:
- value: 创建对象的数值。可以是字符串或者整数。
注意, BigInt() 不是构造函数,因此不能使用 new 操作符。
除了通过BigInt构造函数,我们还可以通过在一个整数字面量后面加 n 的方式定义一个 BigInt ,如:10n
。
例:1
2
3
4let valA = 10n;
let valB = BigInt(10);
console.log(valA === valB); // true
类型判断
我们可以通过typeof操作符来判断是否为BigInt类型(返回字符串"bigint"
),如1
2typeof 1n === 'bigint'; // true
typeof BigInt('1') === 'bigint'; // true
同样的,我们也可以用最通用的Object.prototype.toString方法(返回字符串"[object BigInt]"
)1
Object.prototype.toString.call(10n) === '[object BigInt]'; // true
运算
以下操作符可以和 BigInt 一起使用: +
、*
、-
、**
、%
。除 >>> (无符号右移)之外的 位操作 也可以支持。(因为 BigInt 都是有符号的 >>> (无符号右移)不能用于 BigInt)。
为了兼容 asm.js ,.BigInt 不支持单目 (+) 运算符。
1 | const previousMaxSafe = BigInt(Number.MAX_SAFE_INTEGER); |
当使用 BigInt 时,带小数的运算会被取整。
1 | const expected = 4n / 2n; |
方法
BigInt.asIntN()
将 BigInt 值转换为一个 -2^width - 1 与 2^(width-1) - 1 之间的有符号整数。
语法:1
BigInt.asIntN(width, bigint);
如:1
2
3
4
5
6const max = 2n ** (64n - 1n) - 1n;
BigInt.asIntN(64, max); // 9223372036854775807n
BigInt.asIntN(64, max + 1n); // -9223372036854775807n
// negative because of overflow
BigInt.asUintN()
将一个 BigInt 值转换为 0 与 2^width-1 之间的无符号整数。
语法:1
BigInt.asUintN(width, bigint);
1 | const max = 2n ** 64n - 1n; |
BigInt和Number
BigInt 和 Number 不是严格相等的,但是宽松相等的。
1 | 10n === 10 |
Number 和 BigInt 可以进行比较。
1 | 1n < 2; // true |
两者也可以混在一个数组内并排序。
1 | const mixed = [4n, 6, -12n, 10, 4, 0, 0n]; // [4n, 6, -12n, 10, 4, 0, 0n] |
BigInt 在需要转换成 Boolean 的时表现跟 Number 类似:如通过 Boolean 函数转换;用于 Logical Operators ||, &&
, 和 ! 的操作数;或者用于在像 if statement 这样的条件语句中。
它在某些方面类似于 Number ,但是也有几个关键的不同点:不能用与 Math 对象中的方法;不能和任何 Number 实例混合运算,两者必须转换成同一种类型。在两种类型来回转换时要小心,因为 BigInt 变量在转换成 Number 变量时可能会丢失精度。
不允许隐式类型转换
因为隐式类型转换可能丢失信息,所以不允许在bigint和 Number 之间进行混合操作。当混合使用大整数和浮点数时,结果值可能无法由BigInt或Number精确表示。
如:1
210n + 1; // Uncaught TypeError: Cannot mix BigInt and other types, use explicit conversions
Math.max(2n, 4n, 6n); // TypeError...
BigInt和String
难免会遇到数字和字符串的转换,BigInt也不例外,不过可惜的是BigInt转为String时,其标志性的n
会被省略,如
1 | String(10n); // '10' |
因此也导致以下情况:1
2
3
4
5
6
7
8
9
10
11
12
13
14// array
let arr = [1, 2, 3, 4, 5];
arr[2] === arr[2n]; // true
// object
let obj = {
'1': '1',
'2': '2',
'3': '3',
'4': '4'
};
obj['1'] === obj[1n]; // true
零值
BigInt 没有 Number 的正零(+0
)和负零(-0
)之分。因为 BigInt 表示的是整数
无穷和NaN判断
很有趣的现象
1 | isFinite(10n); // Uncaught TypeError: Cannot convert a BigInt value to a number |
由此我们可以看出isFinite()和Number.isFinite()、isNaN()和Number.isNaN()的区别:isFinite(val)/isNaN(val)的工作机制都是讲参数值val转为数值后再进行比较判断,而Number.isFinite(val)/Number.isNaN(val)则可以理解为直接简单粗暴的变量全等判断(val === Infinity
/val === NaN
)
兼容
(至2019.11.11兼容情况)
如图,兼容情况并不是很好。并且转换BigInt是一个极其复杂的过程,这会导致严重的运行时性能损失。直接polyfill BigInt也是不可能的,因为该提议改变了几个现有操作符的行为。目前,更好的选择是使用JSBI库,它是BigInt提案的纯JS实现,访问地址>>。
使用如下:1
2
3
4
5
6
7
8
9import JSBI from './jsbi.mjs';
const max = JSBI.BigInt(Number.MAX_SAFE_INTEGER);
console.log(String(max));
// → '9007199254740991'
const other = JSBI.BigInt('2');
const result = JSBI.add(max, other);
console.log(String(result));
// → '9007199254740993'
TypeScript
BigInt 类型在 TypeScript3.2 版本被内置,
在TypeScript中,BigInt 和 Number 都是有表示数字的意思,但是实际上两者类型是不同的:
1 | declare let valA: number; |
除了类型定义,TypeScript 中 BigInt 其他使用方法同 ES。
Author
My name is Micheal Wayne and this is my blog.
I am a front-end software engineer.
Contact: michealwayne@163.com