昨天译了一篇文章:BigInt:JavaScript 中的任意精度整数。昨晚又抽空总结了一下 BigInt 的那些坑。
1. 定义形式
BigInt 使用数字字面量加 n 表示支持二进制、八进制、十六进制形式。
对于八进制,只支持新写法 0o064n,不支持旧的写法 0640。
普通写法:
1n
十六进制:
0x6n0X6n
八进制:
0o6n0O6n06n // ❌SyntaxError
二进制:
0b10n0B10n
BigInt不支持科学计数法形式:
1e25n // ❌ SyntaxError
2. 转换为字符串
当作为 key 时,所有值都会被转换为字符串,而 BigInt 转字符串时是没有后缀 n 的。
String(12n) === "12"
因此:
let obj = { };obj[32n] = 1;obj[32] === 1;
数组同理, array[5n] 等同于 array[5] 等同于 array["5"]。
注:这并不意味着 array[xxxn] 和 array[xxx] 是一样的。因为 BigInt 可以超越 Number 的安全表示边界。
let obj = {};obj[9007199254740993n] = "foo";obj[9007199254740993n] === "foo"; // ✅obj["9007199254740993"] === "foo"; // ✅obj[9007199254740993] === "foo"; // ❌
我们可以通过如下代码查一下原因:
let obj = {};obj[9007199254740993n] = "foo";obj[9007199254740993] = "bar";Object.keys(obj);// ["9007199254740993", "9007199254740992"]
因为 String(9007199254740993)==="9007199254740992"。
3. 零值处理
因为 BigInt 表示的是整数,所以只存在一个 0(无正零和负零之分)。
Object.is(-0, 0) === falseObject.is(-0n, 0n) === true
注意: BigInt 中没有 +0n,具体原因见上。
4. 等值判断
BigInt 同值判定规则:
数组:
[0].includes(0n) === false[0n].includes(0n) === true[0n].includes(+0) === false[0n].includes(-0) === false
Set:
new Set([0]).has(0) === truenew Set([0n]).has(0) === falsenew Set([0n]).has(0n) === truenew Set([0]).has(0n) === false
Map:
new Map([[0n, 42]]).has(0n) === truenew Map([[0n, 42]]).has(0) === falsenew Map([[0, 42]]).has(0) === truenew Map([[0, 42]]).has(0n) === false
由于 0 和 0n 不相等,所以在集合中,两者可以共存:
let s = new Set([0, 0n]);s.size === 2;let m = new Map([[0, 42], [0n, 24]]);m.size === 2;
5. 与 Number 比较
BigInt 和 Nubmer 的不同。
BigInt 只有函数,没有构造器,因此不能使用 new 来创建 BigInt 的实例。
new Number(0); // ✅new BigInt(0); // ❌
对某些特殊值的处理不同:
当没有参数时,
Number返回0,BigInt抛出TypeError
Number() // 0BigInt() // ❌ TypeError
当非数字时,
Number返回NaN,BigInt抛出TypeError或SyntaxError
Number(undefined) // NaNBigInt(undefined) // ❌ TypeErrorNumber(null) // 0BigInt(null) // ❌ TypeErrorNumber({}) // NaNBigInt({}) // ❌ SyntaxErrorNumber("foo") // NaNBigInt("foo") // ❌ SyntaxError
两者对于
-0(负零)的处理也不同
Number(-0) === -0BigInt(-0) === 0n
两者都会把
true转换为1,把false转换为0
Number(true) === 1nNumber(false) === 0nBigInt(true) === 1nBigInt(false) === 0n
对于浮点数,
BigInt抛出RangeError异常
BigInt(4.00000001) // ❌ RangeError
对于
NaN和正负无穷,BigInt抛出RangeError异常
BigInt(NaN) // ❌ RangeErrorBigInt(-Infinity) // ❌ RangeErrorBigInt(+Infinity) // ❌ RangeError
6. 类型转换
BigInt 不能隐式转换为 Number,所以在接受 Number 作为参数的运算中,将抛出 TypeError 异常
isNaN(0n) // ❌TypeErrorisFinite(0n) // ❌TypeErrorMath.abs(-4n) // ❌TypeError"bar".substr(1n) // ❌TypeError
但是 Number 下面的函数可以使用:
Number.isSafeInteger(0n) === falseNumber.isFinite(0n) === falseNumber.isNaN(0n) === falseNumber.parseInt(0n) === 0