mengtuifrontend / Blog

芦叶满汀洲,寒沙带浅流。二十年重过南楼。柳下系船犹未稳,能几日,又中秋。 黄鹤断矶头,故人今在否?旧江山浑是新愁。欲买桂花同载酒,终不似,少年游。
18 stars 5 forks source link

BigInt #10

Open diandiandida opened 5 years ago

diandiandida commented 5 years ago

什么是BigInt

js的number是双精度浮点数,安全范围为 2^53-2^53,可以通过 Number.MAX_SAFE_INTEGERNumber.MIN_SAFE_INTEGER 获得具体数值,当初过安全范围时

let maxNum = 9007199254740991

maxNum + 1   // 9007199254740992

maxNum + 2   // 9007199254740992

maxNum + 3   // 9007199254740994

maxNum + 4   // 9007199254740996

maxNum + 5   // 9007199254740996

正常情况下,maxNum + 2 = 9007199254740993,但是超过安全范围后, 任何计算可能会失去精度,在javascript中,大整数ID和高精度的时间戳,没有办法很好的使用 number 类型表示,所以我们基本上会使用字符串来表示这些数字,但是发生计算时,会给开发者带来不便,现在有了 bigint 类型,我们就可以用来表示这些数值,也可以很方便的进行运算。

BigInt -- 是 JavaScript 中的一个新的 数字基本(primitive)类型,可以用任意精度表示整数。使用 BigInt 可以安全的存储和操作大整数,即使这个数超过了 Number 的安全整数范围。BigInt 我们可以执行正确的整数运算而不必担心失去精度。

创建一个BigInt

使用 BigInt(), 这里不需要 newBigInt 只有函数,没有构造器,因此不能使用 new 来创建 BigInt 的实例

// 1.在后面直接添加 n
const firstBigInt = 9007199254740991n

// 2. 使用 BigInt(), 这里不需要 new, BigInt 只有函数,没有构造器,因此不能使用 new 来创建 BigInt 的实例
const secondBigInt = BigInt(9007199254740991) // 9007199254740991n
// 字符串
const thirdBigInt = BigInt("9007199254740991") // 9007199254740991n
// 16进制
const hugeHex = BigInt("0x1fffffffffffff") // 9007199254740991n

类型检测

typeof 12n = "bigint"
typeof BigInt(1) = "bigint"

// 当使用Object包装一下

typeof Object(1n) = "object"

比较

因为 BigInt 是单独的一个类型,所以 BigIntnumber 并不完全相等,如果需要比较的话,可以转换成同一类型,或者使用 ==

2n === 2   // false
2n == 2    // true
2n === 2n  // true

/* number 和 bigint可以照常比较 */
1 < 2n     // true
2n >= 2n   // true
2n > 2     // false

与Number的不同

// 和Number不同,BigInt()没有参数时,会报TypeError,但是Number()返回0

Number()      // 0
BigInt()      // Uncaught 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) === 1
Number(false) === 0

BigInt(true) === 1n
BigInt(false) === 0n

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

BigInt(4.00000001)    // Uncaught RangeError
Number(4.00000001)    // 4.00000001

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

BigInt(NaN) //  RangeError
BigInt(-Infinity) //  RangeError
BigInt(+Infinity) //  RangeError

Number(NaN)     // NaN
Number(-Infinity)       // -Infinity
Number(Infinity)        // Infinity

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

isNaN(0n) // TypeError
isFinite(0n) // TypeError
Math.abs(-4n) // TypeError
"bar".substr(1n) // TypeError

// 部分运算可以使用

Number.isSafeInteger(0n) === false
Number.isFinite(0n) === false
Number.isNaN(0n) === false
Number.parseInt(0n) === 0

//  因为 BigInt表示的是整数,所以只存在一个 0(无正零和负零之分)
 
Object.is(-0, 0) === false
Object.is(-0n, 0n) === true

// 由于 0和 0n不相等,所以在集合中,两者可以共存

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

运算

BIgInt 支持常规的运算符,二元运算符 +,-,*,**,%,按位运算符:|,&,>>,<<,都与number 一致,运算时,不能与 number 混合运算

1n + 1n   // 2n
1n + 1    // error
64n - 12n   // 52n
2n * 2n   // 4n
5n % 2n   // 1n
2n ** 4n   //  16n

1n << 5n    // 32n
1n | 2n    // 3n
1n & 2n    // 0n
16n >> 2n   // 4n

/* 比较运算符 */
if (0n) {
    console.log("if")
} else {
    console.log("else")
}

0n || 12n     // 12n
0n && 12n     // 0n
Boolean(0n)   // false
Boolean(12n)  // true
!12n          // false
!0n           // true

注意:/ 运算符与number不同,有小数舍去 5n / 2n = 2n     // 2.5 12n  / 7n = 1n     // 1.71

方法

BigInt 值封装为有符号或无符号整数,限于特定的位数 (64位),请注意,只要我们传递 BigInt 超过 64位 整数范围的值(例如,绝对数值为63位+符号为1位),就会发生溢出

bigInt.asIntN(width, value):包含-2^(width-1) ~ 2^(width-1)-1 之间的值,包含符号

BigInt.asUintN(): 0 and 2^(width-1)

注意

NumberBigInt 间强制转换,可能导致精度损失,所以建议仅 BigInt 在合理预期大于 2^53 的值时使用,而不是在两种类型之间强制使用

BigInt不适用于密码学。

BigInt只适用于整数

兼容浏览器情况 

​​兼容情况 ​​