We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
BigInt目前已经进入Stage 4阶段 下一个版本将会作为新特性出现在ECMAScript,下面我们来一起了解一下Bigint。
BigInt
Bigint
BigInt是什么? BigInt是JavaScript中一种可以用来表示任意精度整数的基本数据类型
BigInt可以用来表示任意精度整数的特性为JavaScript解锁了更多的骚操作,使用BigInt可以告别过去因为整数运算导致溢出的痛苦。特别是金融方面因为涉及大量的数据运算,比如高精度时间戳,或者数值过大的ID,这些是无法安全的用Number类型去存储的,所以退而求其次使用String类型去存储,有了BigInt类型后就可以安全的将其存储为数值类型。
Number
String
另外BigInt的实现也为实现BigDecimal打下坚实基础,那将对于以十进制精度表示货币金额并对其进行精确运算(也就是0.10 + 0.20 !== 0.30问题)非常有帮助
BigDecimal
0.10 + 0.20 !== 0.30
此前已经有不少库实现了BigInt式的整数存储,当BigInt完全可用时,就可以拿掉那些依赖了,因为相比于使用这些依赖库,Native BigInt则更具优势。因为与之相比,NativeBigInt不需要加载解析编译的额外时间,并且在性能上表现更好。
JavaScript中Number是以64位双精度浮点型存储,所以会有精度限制,JavaScript中可以准确表示的最大整数是Number.MAX_SAFE_INTEGER这个值是2^53-1
Number.MAX_SAFE_INTEGER
2^53-1
const max = Number.MAX_SAFE_INTEGER; // → 9_007_199_254_740_991
Tips:为了可读性使用下划线作为分隔符进行分组 The numeric literal separators proposal
当自增一次时,可以得到正确值:
max + 1; // 9_007_199_254_740_992 ✅
当自增两次时,我们发现结果并非预期
max + 2; // → 9_007_199_254_740_992 ❌
max+1 和max+2的结果一致,这就导致我们无法保证在JavaScript中获取到的这个值的准确性,JavaScript中任何超出安全值范围的计算都会丢失精度,正因为如此我们只能信任安全值范围内的整数。
max+1
max+2
BigInt是JavaScript中一种可以用来表示任意精度(arbitrary precision)整数的基本数据类型,使用BigInt可以安全的存储和操作任意大小的整数而不受Number类型的安全值范围的限制。
生成一个BigInt类型的值只需要在任意整数后加上n做后缀即可。例如:123 用BigInt类型表示123n,也可以通过全局函数BigInt(number)来将Number类型转化为BigInt类型,换言之BigInt(123) === 123n,让我们用BigInt来解决一下上文所提到的问题
123
123n
BigInt(number)
BigInt(123) === 123n
BigInt(Number.MAX_SAFE_INTEGER) + 2n; // 9_007_199_254_740_993n ✅
再看一个两个Number类型的数值相乘的例子
1234567890123456789*123; // -> 151851850485185200000 ❌
仔细看这个结果肯定是不对的,因为最低位一个是9一个是3所以正确值肯定是以7结尾的(3*9=27),但是这里却是一串0结尾,我们来用BigInt重新计算一下
1234567890123456789n*123n; // -> 151851850485185185047n ✅
很显然这次是对的,当我们用BigInt来处理时不会受到Number中的安全值范围的限制,所以不用担心精度丢失
BigInt是JavaScript中新的的基础类型,所以可以用typeof操作符去检测
typeof
typeof 123 // 'number' typeof 123n // 'bigint'
因为Bigint是一个单独的类型,所以BigInt类型值和Number严格模式下不相等,e.g. 4!== 4n,BigInt类型和Number类型作比较时需要将自身类型转化为相互的类型,或者直接使用严格相等(===)
4!== 4n
4n === BigInt(4); // => true 4n == 4; // => true 4n === 4; // => false
当强制类型转化为布尔值时(例如在使用if,&&,||,或者Boolean(int)时触发),BigInt遵循和Numebr一样的规则
if
&&
||
Boolean(int)
Numebr
if(0n){ console.log('if'); }else{ console.log('else'); } // 输出:'else', 因为0n是假值 0n || 12n // -> 12n 0n && 12n // -> 0n Boolean(0n); // -> false Boolean(12n); // -> true !12n // -> false !0n // -> true
BigInt支持那些常见的运算符例如:+,-,*,/ ** %,包括一些按位运算符如|, & , <<, >> ^ ,它和Number类型值的表现一致
+,-,*,/ ** %
|, & , <<, >> ^
(7 + 6 - 5) * 4 ** 3 / 2 % 3; // → 1 (7n + 6n - 5n) * 4n ** 3n / 2n % 3n; // → 1n
一元运算符-可以用来表示BigInt中的负数,如:-42n ,但是一元运算符+不支持,因为如果支持则会导致+x表示结果为非Number值,从而引起和现有逻辑的冲突。
-
+
+x
一个值得注意的点是不要混合操作BigInt类型和Number类型,因为任何隐式强制类型转化都会导致精度丢失,看下面的例子:
BigInt(Number.MAX_SAFE_INTEGER)+2.5 // => ?? 🤔
可以猜一下结果,其实并没有合理的答案。因为BigInt无法表示小数,而Number则无法正确表示BigInt类型的超出安全范围的值,因此当混用BigInt和Number时会报TypeError
TypeError
其中唯一的例外是比较运算符,比如 === < > <= >=等,因为这类操作符最终会返回一个布尔类型值,不存在精度丢失的情况:
===
<
>
<=
>=
1+1n // -> TypeError 123<124n; // -> true
建议:BigInt和Number一般情况下不要混合操作,BigInt对于可能操作较大整数的情况下是合理的选择,Number则对于在安全值范围内的操作更合适,所以选定一种合适的类型用下去,不要相互混用。
注意⚠️:额外需要注意的一点是无符号右移操作符>>>,因为BigInt始终是有符号的所以无符号右移操作符对于BigInt来说不会生效。
关于BigInt的几个API BigInt() BigInt.asIntN(width, value) BigInt.asUintN(width, value) BigInt64Array,BigUint64Array
BigInt()
BigInt.asIntN(width, value)
BigInt.asUintN(width, value)
BigInt64Array
BigUint64Array
SyntaxError
RangeError
BigInt(123); // -> 123n BigInt(1.2); // -> RangeError BigInt('1.2'); // -> SyntaxError
BigInt.asIntN(width,value)
BigInt.asUintN(width,value)
// BigInt类型值所能表示的最大的有符号的64位整数值 const max = 2n**(64n - 1n) - 1n; BigInt.asIntN(64,max); // -> 9_223_372_036_854_775_807n BigInt.asIntN(64, max+1n); // -> -9_223_372_036_854_775_808n // ^ 变为负值 因为溢出了 // 一旦传给超过64位整数范围(即63位的绝对数值+1位符号位)的BigInt值,就会发生溢出。 BigInt.asUintN(64,max); // -> 9_223_372_036_854_775_807n BigInt.asUintN(64,max+1n) // -> 9_223_372_036_854_775_808n
const view = new BigInt64Array(4); // -> [0n,0n,0n,0n] view.length; // -> 4 view[0]; // -> 0n view[0] = 40n; view[0]; // -> 40n
BigInt64Array可以确保其值保持在有符号的64位限制范围内。BigUint64Array则确保其值保持在无符号位的64位限制范围内
// BigInt类型值所能表示的最大的有符号的64位整数值 const max = 2n**(64n - 1n) - 1n; view[0] = max; view[0] // -> 9_223_372_036_854_775_807n view[0] = max + 1n; view[0]; // -> -9_223_372_036_854_775_808n // ^ 溢出了 const view_u = new BigUint64Array(4); view_u[0] = max; view_u[0]; // -> 9_223_372_036_854_775_807n view_u[0] = max+1n; view_u[0]; // -> 9_223_372_036_854_775_808n
到目前为止已经实现BigInt的有Chrome(67+),Firefox(68+),Opear(54+),Node(10.4.0 +),其中Safari正在实现中
参考链接:
想知道BigInt是如何在Chrome中的实现的吗?请看下篇BigInt在V8中的实现(还没写呢)loading...
The text was updated successfully, but these errors were encountered:
No branches or pull requests
BigInt
BigInt
目前已经进入Stage 4阶段 下一个版本将会作为新特性出现在ECMAScript,下面我们来一起了解一下Bigint
。BigInt
是什么?BigInt
是JavaScript中一种可以用来表示任意精度整数的基本数据类型BigInt
可以用来表示任意精度整数的特性为JavaScript解锁了更多的骚操作,使用BigInt
可以告别过去因为整数运算导致溢出的痛苦。特别是金融方面因为涉及大量的数据运算,比如高精度时间戳,或者数值过大的ID,这些是无法安全的用Number
类型去存储的,所以退而求其次使用String
类型去存储,有了BigInt
类型后就可以安全的将其存储为数值类型。另外
BigInt
的实现也为实现BigDecimal
打下坚实基础,那将对于以十进制精度表示货币金额并对其进行精确运算(也就是0.10 + 0.20 !== 0.30
问题)非常有帮助此前已经有不少库实现了BigInt式的整数存储,当BigInt完全可用时,就可以拿掉那些依赖了,因为相比于使用这些依赖库,Native
BigInt
则更具优势。因为与之相比,NativeBigInt
不需要加载解析编译的额外时间,并且在性能上表现更好。图示为BigInt与其他流行库在Chrome中的表现情况对比(值越大表现越好)
现状:Number
JavaScript中Number是以64位双精度浮点型存储,所以会有精度限制,JavaScript中可以准确表示的最大整数是
Number.MAX_SAFE_INTEGER
这个值是2^53-1
Tips:为了可读性使用下划线作为分隔符进行分组 The numeric literal separators proposal
当自增一次时,可以得到正确值:
当自增两次时,我们发现结果并非预期
max+1
和max+2
的结果一致,这就导致我们无法保证在JavaScript中获取到的这个值的准确性,JavaScript中任何超出安全值范围的计算都会丢失精度,正因为如此我们只能信任安全值范围内的整数。新热点:BigInt
BigInt
是JavaScript中一种可以用来表示任意精度(arbitrary precision)整数的基本数据类型,使用BigInt
可以安全的存储和操作任意大小的整数而不受Number
类型的安全值范围的限制。生成一个
BigInt
类型的值只需要在任意整数后加上n做后缀即可。例如:123
用BigInt
类型表示123n
,也可以通过全局函数BigInt(number)
来将Number
类型转化为BigInt
类型,换言之BigInt(123) === 123n
,让我们用BigInt
来解决一下上文所提到的问题再看一个两个Number类型的数值相乘的例子
仔细看这个结果肯定是不对的,因为最低位一个是9一个是3所以正确值肯定是以7结尾的(3*9=27),但是这里却是一串0结尾,我们来用BigInt重新计算一下
很显然这次是对的,当我们用
BigInt
来处理时不会受到Number
中的安全值范围的限制,所以不用担心精度丢失BigInt
是JavaScript中新的的基础类型,所以可以用typeof
操作符去检测因为
Bigint
是一个单独的类型,所以BigInt
类型值和Number
严格模式下不相等,e.g.4!== 4n
,BigInt类型和Number类型作比较时需要将自身类型转化为相互的类型,或者直接使用严格相等(===)当强制类型转化为布尔值时(例如在使用
if
,&&
,||
,或者Boolean(int)
时触发),BigInt
遵循和Numebr
一样的规则BigInt支持那些常见的运算符例如:
+,-,*,/ ** %
,包括一些按位运算符如|, & , <<, >> ^
,它和Number类型值的表现一致一元运算符
-
可以用来表示BigInt中的负数,如:-42n ,但是一元运算符+
不支持,因为如果支持则会导致+x
表示结果为非Number
值,从而引起和现有逻辑的冲突。一个值得注意的点是不要混合操作BigInt类型和Number类型,因为任何隐式强制类型转化都会导致精度丢失,看下面的例子:
可以猜一下结果,其实并没有合理的答案。因为
BigInt
无法表示小数,而Number
则无法正确表示BigInt
类型的超出安全范围的值,因此当混用BigInt
和Number
时会报TypeError
其中唯一的例外是比较运算符,比如
===
<
>
<=
>=
等,因为这类操作符最终会返回一个布尔类型值,不存在精度丢失的情况:建议:BigInt和
Number
一般情况下不要混合操作,BigInt
对于可能操作较大整数的情况下是合理的选择,Number
则对于在安全值范围内的操作更合适,所以选定一种合适的类型用下去,不要相互混用。注意⚠️ :额外需要注意的一点是无符号右移操作符>>>,因为BigInt始终是有符号的所以无符号右移操作符对于BigInt来说不会生效。
API
关于BigInt的几个API
BigInt()
BigInt.asIntN(width, value)
BigInt.asUintN(width, value)
BigInt64Array
,BigUint64Array
BigInt
函数,这个BigInt全局构造函数和Number
的构造函数类似,将传入的参数转化为BigInt
类型,如果转化失败,会报SyntaxError
或者RangeError
BigInt.asIntN(width, value)
BigInt.asUintN(width, value)
,通过这两个库函数,可以将BigInt值包装为有符号或无符号整数,并限制在特定位数。其中BigInt.asIntN(width,value)
将BigInt
类型值包装为有符号二进制整数,BigInt.asUintN(width,value)
将BigInt类型值包装为无符号二进制整数。例如:如果你要执行64位算术运算,则可以使用它们来将其保持在适当的范围内:BigInt64Array
和BigUint64Array
可以使我们更加容易且有效地表示和操作此类值的列表。BigInt64Array
可以确保其值保持在有符号的64位限制范围内。BigUint64Array
则确保其值保持在无符号位的64位限制范围内兼容性
到目前为止已经实现
BigInt
的有Chrome(67+),Firefox(68+),Opear(54+),Node(10.4.0+),其中Safari正在实现中
参考链接:
想知道BigInt是如何在Chrome中的实现的吗?请看下篇BigInt在V8中的实现(还没写呢)loading...
The text was updated successfully, but these errors were encountered: