Javascript 提案 BigInt 的一些坑

本文总结了JavaScript中BigInt类型的使用陷阱,包括定义形式(支持二进制、八进制、十六进制,不支持科学计数法)、转换为字符串时无后缀、仅有一个零值、等值判断的特例、与Number比较的差异以及类型转换的限制。通过实例展示了BigInt在数组、集合、比较和类型转换等方面需要注意的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

昨天译了一篇文章:BigInt:JavaScript 中的任意精度整数。昨晚又抽空总结了一下 BigInt 的那些坑。

1. 定义形式

BigInt 使用数字字面量加 n 表示支持二进制、八进制、十六进制形式。

对于八进制,只支持新写法 0o064n,不支持旧的写法 0640

  1. 普通写法:


 
  1. 1n

  1. 十六进制:


 
  1. 0x6n

  2. 0X6n

  1. 八进制:


 
  1. 0o6n

  2. 0O6n

  3. 06n  // ❌SyntaxError

  1. 二进制:


 
  1. 0b10n

  2. 0B10n

  1. BigInt 不支持科学计数法形式:


 
  1. 1e25n // ❌ SyntaxError

2. 转换为字符串

当作为 key 时,所有值都会被转换为字符串,而 BigInt 转字符串时是没有后缀 n 的。


 
  1. String(12n) === "12"

因此:


 
  1. let obj = { };

  2. obj[32n] = 1;

  3. obj[32] === 1;

数组同理, array[5n] 等同于 array[5] 等同于 array["5"]

:这并不意味着 array[xxxn]array[xxx] 是一样的。因为 BigInt 可以超越 Number 的安全表示边界。


 
  1. let obj = {};

  2. obj[9007199254740993n] = "foo";

  3. obj[9007199254740993n] === "foo"; // ✅

  4. obj["9007199254740993"] === "foo"; // ✅

  5. obj[9007199254740993] === "foo"; // ❌

我们可以通过如下代码查一下原因:


 
  1. let obj = {};

  2. obj[9007199254740993n] = "foo";

  3. obj[9007199254740993] = "bar";

  4. Object.keys(obj);

  5. // ["9007199254740993", "9007199254740992"]

因为 String(9007199254740993)==="9007199254740992"

3. 零值处理

因为 BigInt 表示的是整数,所以只存在一个 0(无正零和负零之分)。


 
  1. Object.is(-0, 0) === false

  2. Object.is(-0n, 0n) === true

注意BigInt 中没有 +0n,具体原因见上。

4. 等值判断

BigInt 同值判定规则:

  1. 数组:


 
  1. [0].includes(0n) === false

  2. [0n].includes(0n) === true

  3. [0n].includes(+0) === false

  4. [0n].includes(-0) === false

  1. Set


 
  1. new Set([0]).has(0) === true

  2. new Set([0n]).has(0) === false

  3. new Set([0n]).has(0n) === true

  4. new Set([0]).has(0n) === false

  1. Map


 
  1. new Map([[0n, 42]]).has(0n) === true

  2. new Map([[0n, 42]]).has(0) === false

  3. new Map([[0, 42]]).has(0) === true

  4. new Map([[0, 42]]).has(0n) === false

由于 00n 不相等,所以在集合中,两者可以共存:


 
  1. let s = new Set([0, 0n]);

  2. s.size === 2;

  3. let m = new Map([[0, 42], [0n, 24]]);

  4. m.size === 2;

5. 与 Number 比较

BigIntNubmer 的不同。

BigInt 只有函数,没有构造器,因此不能使用 new 来创建 BigInt 的实例。


 
  1. new Number(0); // ✅

  2. new BigInt(0); // ❌

对某些特殊值的处理不同:

  1. 当没有参数时, Number 返回 0, BigInt 抛出 TypeError


 
  1. Number() // 0

  2. BigInt() // ❌ TypeError

  1. 当非数字时, Number 返回 NaN, BigInt 抛出 TypeError 或 SyntaxError


 
  1. Number(undefined) // NaN

  2. BigInt(undefined) // ❌ TypeError

  3. Number(null) // 0

  4. BigInt(null) // ❌ TypeError

  5. Number({}) // NaN

  6. BigInt({}) // ❌ SyntaxError

  7. Number("foo")  // NaN

  8. BigInt("foo") // ❌ SyntaxError

  1. 两者对于 -0(负零)的处理也不同


 
  1. Number(-0) === -0

  2. BigInt(-0) === 0n

  1. 两者都会把 true 转换为 1,把 false 转换为 0


 
  1. Number(true) === 1n

  2. Number(false) === 0n

  3. BigInt(true) === 1n

  4. BigInt(false) === 0n

  1. 对于浮点数, BigInt 抛出 RangeError 异常


 
  1. BigInt(4.00000001) // ❌ RangeError

  1. 对于 NaN 和正负无穷, BigInt 抛出 RangeError 异常


 
  1. BigInt(NaN) // ❌ RangeError

  2. BigInt(-Infinity) // ❌ RangeError

  3. BigInt(+Infinity) // ❌ RangeError

6. 类型转换

BigInt 不能隐式转换为 Number,所以在接受 Number 作为参数的运算中,将抛出 TypeError 异常


 
  1. isNaN(0n) // ❌TypeError

  2. isFinite(0n) // ❌TypeError

  3. Math.abs(-4n) // ❌TypeError

  4. "bar".substr(1n) // ❌TypeError

但是 Number 下面的函数可以使用:


 
  1. Number.isSafeInteger(0n) === false

  2. Number.isFinite(0n) === false

  3. Number.isNaN(0n) === false

  4. Number.parseInt(0n) === 0

7. 继续阅读

640?wx_fmt=png


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值