昨天译了一篇文章:BigInt:JavaScript 中的任意精度整数。昨晚又抽空总结了一下 BigInt
的那些坑。
1. 定义形式
BigInt
使用数字字面量加 n
表示支持二进制、八进制、十六进制形式。
对于八进制,只支持新写法 0o064n
,不支持旧的写法 0640
。
普通写法:
1n
十六进制:
0x6n
0X6n
八进制:
0o6n
0O6n
06n // ❌SyntaxError
二进制:
0b10n
0B10n
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) === false
Object.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) === true
new Set([0n]).has(0) === false
new Set([0n]).has(0n) === true
new Set([0]).has(0n) === false
Map
:
new Map([[0n, 42]]).has(0n) === true
new Map([[0n, 42]]).has(0) === false
new Map([[0, 42]]).has(0) === true
new 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() // 0
BigInt() // ❌ TypeError
当非数字时,
Number
返回NaN
,BigInt
抛出TypeError
或SyntaxError
Number(undefined) // NaN
BigInt(undefined) // ❌ TypeError
Number(null) // 0
BigInt(null) // ❌ TypeError
Number({}) // NaN
BigInt({}) // ❌ SyntaxError
Number("foo") // NaN
BigInt("foo") // ❌ SyntaxError
两者对于
-0
(负零)的处理也不同
Number(-0) === -0
BigInt(-0) === 0n
两者都会把
true
转换为1
,把false
转换为0
Number(true) === 1n
Number(false) === 0n
BigInt(true) === 1n
BigInt(false) === 0n
对于浮点数,
BigInt
抛出RangeError
异常
BigInt(4.00000001) // ❌ RangeError
对于
NaN
和正负无穷,BigInt
抛出RangeError
异常
BigInt(NaN) // ❌ RangeError
BigInt(-Infinity) // ❌ RangeError
BigInt(+Infinity) // ❌ RangeError
6. 类型转换
BigInt
不能隐式转换为 Number
,所以在接受 Number
作为参数的运算中,将抛出 TypeError
异常
isNaN(0n) // ❌TypeError
isFinite(0n) // ❌TypeError
Math.abs(-4n) // ❌TypeError
"bar".substr(1n) // ❌TypeError
但是 Number
下面的函数可以使用:
Number.isSafeInteger(0n) === false
Number.isFinite(0n) === false
Number.isNaN(0n) === false
Number.parseInt(0n) === 0
7. 继续阅读
本文分享自微信公众号 - justjavac(justjavac-blog)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。