浅析JS中的BigInt类型及其使用方法与注意事项

一、Number 的安全范围

  和别的强类型编程语言(比如说 C,Java)不同,JavaScript 不区分整数值和浮点数值。我们可以发现 10 === 10.0 为 true,那是因为 JavaScript 的数字类型是基于 IEEE 754 标准中的"双精度"格式,也就是 64 位二进制来实现的,它是通过如下格式来存储数据。

  符号位(Sign bit): 1 bit(0 表示正数, 1 表示负数)

  指数位(Exponent): 11 bits

  有效数字(Significand precision): 53 bits (52 explicitly stored)在二进制中,计算机内部保存有效数字时,第一个有效数字必定是1,因此这个1并不会存储。所以52位有效数字可以存储53位。

  这里可以提到的的一点是:二进制浮点数最大的问题就是在处理0.1 + 0.2的时候,实际上的结果不是0.3,而是一个比较接近的数字0.30000000000000004,这也是因为在它计算的时候,会先转化为二进制,再进行计算导致的偏差。因为我们在用 JavaScript 或者其他遵循 IEEE 754 规范的语言处理带有效数的数字时要特别注意

JavaScript 的数字格式也就决定了 JavaScript 能够安全表示的整数范围是 -2^53+1 ~ 2^53-1。这里我们可以先明确一下“安全”的概念:

(1)可以准确地表示为一个 IEEE-754 双精度数字

(2)其 IEEE-754 表示不能是舍入任何其他整数以适应 IEEE-754 表示的结果

  比如说 2^53 - 1 是一个安全整数,它能被精确表示,在任何 IEEE-754 舍入模式(rounding mode)下,没有其他整数舍入结果为该整数。作为对比,2^53 就不是一个安全整数,它能够使用 IEEE-754 表示,但是 2^53 + 1 不能使用 IEEE-754 直接表示,在就近舍入(round-to-nearest)和向零舍入中,会被舍入为 2^53

  可以参考Number.isSafeInteger()的定义。

二、BigInt 类型

  在 ES2020 之前,JavaScript 只有一种数值类型:number(数字),而之后为了安全表达比 -9007199254740991 ~ 9007199254740991安全范围之外的数字。引入了BigInt类型。

  一般计算机是将整数存储在 CPU 的寄存器中(现在通常是 32 位或 64 位宽, JS 是 64bit),或者存储在寄存器大小的内存块中,这就会带来安全范围的问题。而 BigInt 类型为了保证精度。它是在内存中分配一个对象。我们让它足够大,以一系列块的形式容纳所有 BigInt 的位,我们称之为“数字”。

  BigInt 是一种内置对象,它提供了一种方法来表示大于 2^53 - 1 的整数。这原本是 Javascript 中可以用 Number 表示的最大数字。BigInt 可以表示任意大的整数。

三、如何使用

1、直接在数字后面加一个n
2、调用BigInt()构造函数
const bigInt = 9007199254740992n; //通过直接在数字后面加n
const bigNumber = BigInt(9007199254740992); // 对十进制数字使用BigInt函数
const bigString = BigInt("9007199254740992"); //对String类型的使用BigInt函数,先隐式转换为十进制的数字,再显式转换为BigIn类型
const bigHex = BigInt(0x20000000000000); // 对十六进制数字使用BigInt函数
const bigBin = BigInt(0b100000000000000000000000000000000000000000000000000000); //对二进制数字使用BigInt函数

3、类型信息:使用 typeof 测试时, BigInt 对象返回 "bigint" :

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

// 使用 Object 包装后, BigInt 被认为是一个普通 "object" 
typeof Object(1n) === 'object'; // true

四、bigint 使用注意事项

  BigInt 类型虽然和 Number 很像,可以做各种数学运算,但是在运算过程中要注意两点:

1、BigInt 类型不能用 Math 对象中的方法。

2、不能和 Number 示例混合运算。因为 JavaScript 在处理不同类型的运算时,会把他们先转换为同一类型,而 BigInt 类型变量在被隐式转换为 Number 类型时,可能会丢失精度,或者直接报错。

const number = 1;
const bigInt = 9007199254740993n;
number + bigInt; //  TypeError: Cannot mix BigInt and other types
3、BigInt 类型的比较和 JavaScript 中的其他类型比较一样,分为宽松相等和严格相等。
const bigInt = 2n;
const int = 2;
const string = "2";
bigInt == int; // true
bigInt == string; // true

bigInt === int; // false
bigInt === string; //false

4、在 JSON 中使用

  对任何 BigInt 值使用 JSON.stringify() 都会引发 TypeError,因为默认情况下 BigInt 值不会在 JSON 中序列化。但是,如果需要,可以实现 toJSON 方法:

BigInt.prototype.toJSON = function() { return this.toString(); }

// JSON.stringify 现在生成如下字符串,而不是抛出异常:
JSON.stringify(BigInt(1));  // '"1"'

5、使用 BigInt 运算时,带小数的结果会被取整。如 5n / 2n = 2 ,而不是 2.5

posted @ 2018-02-24 18:31  古兰精  阅读(1155)  评论(0编辑  收藏  举报