详解BigInt

2019-09-20

为什么要有BigInt

9999999999999999 === 10000000000000000  // true

上述等式,返回true。如果代码里出现这种迷惑性的bug,排查起来会非常头疼。


JavaScript中Number类型只能安全地表示-9007199254740991 (-(2^53-1)) 到
 9007199254740991(2^53-1)之间的整数,超出此范围的整数可能失去精度。因此大数不能直接用Number类型来计算,比如加减运算,需要把Number类型转换成String类型,再逐位加减。(这是很多大厂前端笔试的编程题,建议新手自己写下试试,指不定哪天面试就用上了。)


虽然也有很多专门做大数计算的第三方库,如bn.js、bigi、math.js等,但原理都是转换类型、拆成多个数字、分别计算之后再合成结果,这会消耗很多额外的性能。开发者希望JavaScript能有原生的方法实现大数计算,来减少加载、解析和编译的时间,提高运行性能。这就是BigInt。


下文会频繁用一个常量:Number.MAX_SAFE_INTEGER。它表示Number类型能安全表示的最大的整数 9007199254740991。


BigInt是什么

BigInt最新的 ECMAScript标准 定义的7种基础数据类型之一,可以表示任意大的整数。

BigInt有两种创建方式:在整数后面加“n”,或者使用构造函数BigInt():

const a = 9007199254740991;            //创建Number类型的变量
const b = 9007199254740991n;           //在整数后加n创建BigInt类型的变量
const c = BigInt(9007199254740991);    //把Number类型转成BigInt类型
const d = Number(9007199254740991n);   //把BigInt类型转成Number类型(可能会丢失精度)
const e = BigInt('9007199254740991');  //构造函数用String类型创建BigInt类型
const f = BigInt('0x1fffffffffffff');  //构造函数用十六进制创建BigInt类型

请注意,用BigInt()构造函数可以安全地把不超过上限的Number类型转换成BigInt类型,但反过来用Numbre()构造函数转换超过上限的BigInt类型数据可能会丢失精度。


BigInt是基础数据类型之一,意味着可以用typeof来判断数据类型:

typeof 1n === 'bigint'; // true
typeof BigInt('1') === 'bigint'; // true


BigInt不能和Number混合运算,否则会抛出错误。BigInt也不能用Math对象中的方法,因为Math处理的是Number类型的数据。

1n + 1
// Uncaught TypeError: Cannot mix BigInt and other types, use explicit conversions
Math.abs(1n)
// Uncaught TypeError: Cannot convert a BigInt value to a number


BigInt怎么用

运算

BigInt可以直接使用加减乘除等运算符:

const a = BigInt(5n);
let b = a+2n;  //7n(加)
let c = a-1n;  //4n(减)
let d = a*2n;  //10n(乘)
let e = a/2n;  //2n(除)
let f = a%3n;  //2n(取余)
let g = a**3n; //1000n(幂)

BigInt不能储存小数,因此除法预算的时候,结果会进行取整。


比较

BigInt可以直接使用比较运算符,甚至可以和Number类型混合比较和排序:

1n === 1 //false
1n == 1  //true
1n < 2n   //true
1n >= 2  //false

const arr = [2n, 3, -5n, 4, 0, 0n];
arr.sort();  //[-5n, 0, 0n, 2n, 3, 4]


逻辑

BigInt在逻辑运算时表现和Number非常相似:

0n && 1n    // 0n
0n || 1n    // 1n
!!0n        // false
!!1n        // true
Boolean(0n) // false
Boolean(1n) // true


其他

BigInt还提供了一些常用的实例方法,表现也跟Number非常相似:

const a = BigInt(Number.MAX_SAFE_INTEGER); //9007199254740991n
let b = a.toLocaleString();                //"9,007,199,254,740,991"
let c = a.toString();                      //"9007199254740991"
let d = a.valueOf();                       //9007199254740991n


总结

BigInt实现了原生的大数计算。像我们这些做金融的,对计算的性能和准确性有极高的要求,对BigInt寄予厚望。只可惜目前仅有新版本的Chrome、Firefox支持,其他的IE和Safari都不支持,暂时不推荐在浏览器环境使用。


参考文献

  1. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt



本文未经许可禁止转载,如需转载关注微信公众号【工程师加一】并留言。