为什么要有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都不支持,暂时不推荐在浏览器环境使用。
参考文献
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt
本文未经许可禁止转载,如需转载关注微信公众号【工程师加一】并留言。