资讯专栏INFORMATION COLUMN

JS最新基本数据类型:BigInt

lwx12525 / 1542人阅读

摘要:意外四舍五入会损害程序的可靠性和安全性。下面是一些例子构造函数与其他基本类型一样,可以使用构造函数创建。总结是一种新的数据类型,用于当整数值大于数据类型支持的范围时。

为了保证的可读性,本文采用意译而非直译。

想阅读更多优质文章请猛戳GitHub博客,一年百来篇优质文章等着你!

BigInt数据类型的目的是比Number数据类型支持的范围更大的整数值。在对大整数执行数学运算时,以任意精度表示整数的能力尤为重要。使用BigInt,整数溢出将不再是问题。

此外,可以安全地使用更加准确时间戳,大整数ID等,而无需使用变通方法。 BigInt目前是第3阶段提案, 一旦添加到规范中,它就是JS 第二个数字数据类型,也将是 JS 第8种基本数据类型:

Boolean

Null

Undefined

Number

BigInt

String

Symbol

Object

在本文中,咱们将详细介绍BigInt,看看它如何解决使用Number类型的限制。

问题

对于学过其他语言的程序员来说,JS中缺少显式整数类型常常令人困惑。许多编程语言支持多种数字类型,如浮点型、双精度型、整数型和双精度型,但JS却不是这样。在JS中,按照IEEE 754-2008标准的定义,所有数字都以双精度64位浮点格式表示。

在此标准下,无法精确表示的非常大的整数将自动四舍五入。确切地说,JS 中的Number类型只能安全地表示-9007199254740991 (-(2^53-1))9007199254740991(2^53-1)之间的整数,任何超出此范围的整数值都可能失去精度。

console.log(9999999999999999);    // → 10000000000000000

该整数大于JS Number 类型所能表示的最大整数,因此,它被四舍五入的。意外四舍五入会损害程序的可靠性和安全性。这是另一个例子:

// 注意最后一位的数字
9007199254740992 === 9007199254740993;    // → true

JS 提供Number.MAX_SAFE_INTEGER常量来表示 最大安全整数,Number.MIN_SAFE_INTEGER常量表示最小安全整数:

const minInt = Number.MIN_SAFE_INTEGER;

console.log(minInt);         // → -9007199254740991

console.log(minInt - 5);     // → -9007199254740996

// notice how this outputs the same value as above
console.log(minInt - 4);     // → -9007199254740996
解决方案

为了解决这些限制,一些JS开发人员使用字符串类型表示大整数。 例如,Twitter API 在使用 JSON 进行响应时会向对象添加字符串版本的 ID。 此外,还开发了许多库,例如 bignumber.js,以便更容易地处理大整数。

使用BigInt,应用程序不再需要变通方法或库来安全地表示Number.MAX_SAFE_INTEGERNumber.Min_SAFE_INTEGER之外的整数。 现在可以在标准JS中执行对大整数的算术运算,而不会有精度损失的风险。

要创建BigInt,只需在整数的末尾追加n即可。比较:

console.log(9007199254740995n);    // → 9007199254740995n
console.log(9007199254740995);     // → 9007199254740996

或者,可以调用BigInt()构造函数

BigInt("9007199254740995");    // → 9007199254740995n

BigInt文字也可以用二进制、八进制或十六进制表示

// binary
console.log(0b100000000000000000000000000000000000000000000000000011n);
// → 9007199254740995n

// hex
console.log(0x20000000000003n);
// → 9007199254740995n

// octal
console.log(0o400000000000000003n);
// → 9007199254740995n

// note that legacy octal syntax is not supported
console.log(0400000000000000003n);
// → SyntaxError

请记住,不能使用严格相等运算符将BigInt与常规数字进行比较,因为它们的类型不同:

console.log(10n === 10);    // → false

console.log(typeof 10n);    // → bigint
console.log(typeof 10);     // → number

相反,可以使用等号运算符,它在处理操作数之前执行隐式类型转换

console.log(10n == 10);    // → true

除一元加号(+)运算符外,所有算术运算符都可用于BigInt

10n + 20n;    // → 30n
10n - 20n;    // → -10n
+10n;         // → TypeError: Cannot convert a BigInt value to a number
-10n;         // → -10n
10n * 20n;    // → 200n
20n / 10n;    // → 2n
23n % 10n;    // → 3n
10n ** 3n;    // → 1000n

const x = 10n;
++x;          // → 11n
--x;          // → 9n

不支持一元加号(+)运算符的原因是某些程序可能依赖于+始终生成Number的不变量,或者抛出异常。 更改+的行为也会破坏asm.js代码。

当然,与BigInt操作数一起使用时,算术运算符应该返回BigInt值。因此,除法(/)运算符的结果会自动向下舍入到最接近的整数。例如:

25 / 10;      // → 2.5
25n / 10n;    // → 2n

隐式类型转换

因为隐式类型转换可能丢失信息,所以不允许在bigintNumber 之间进行混合操作。当混合使用大整数和浮点数时,结果值可能无法由BigIntNumber精确表示。思考下面的例子:

(9007199254740992n + 1n) + 0.5

这个表达式的结果超出了BigIntNumber的范围。小数部分的Number不能精确地转换为BigInt。大于2^53BigInt不能准确地转换为数字。

由于这个限制,不可能对混合使用NumberBigInt操作数执行算术操作。还不能将BigInt传递给Web api和内置的 JS 函数,这些函数需要一个 Number 类型的数字。尝试这样做会报TypeError错误

10 + 10n;    // → TypeError
Math.max(2n, 4n, 6n);    // → TypeError

请注意,关系运算符不遵循此规则,如下例所示:

10n > 5;    // → true

如果希望使用BigIntNumber执行算术计算,首先需要确定应该在哪个类型中执行该操作。为此,只需通过调用Number()BigInt()来转换操作数:

BigInt(10) + 10n;    // → 20n
// or
10 + Number(10n);    // → 20

Boolean 类型与BigInt 类型相遇时,BigInt的处理方式与Number类似,换句话说,只要不是0nBigInt就被视为truthy的值:

if (5n) {
    // 这里代码块将被执行
}

if (0n) {
    // 这里代码块不会执行
}

排序BigIntsNumbers数组时,不会发生隐式类型转换:

const arr = [3n, 4, 2, 1n, 0, -1n];

arr.sort();    // → [-1n, 0, 1n, 2, 3n, 4]

位操作符如|、&、<<、>>^Bigint的操作方式与Number类似。下面是一些例子

90 | 115;      // → 123
90n | 115n;    // → 123n
90n | 115;     // → TypeError
BigInt构造函数

与其他基本类型一样,可以使用构造函数创建BigInt。传递给BigInt()的参数将自动转换为BigInt:

BigInt("10");    // → 10n
BigInt(10);      // → 10n
BigInt(true);    // → 1n

无法转换的数据类型和值会引发异常:

BigInt(10.2);     // → RangeError
BigInt(null);     // → TypeError
BigInt("abc");    // → SyntaxError

可以直接对使用构造函数创建的BigInt执行算术操作

BigInt(10) * 10n;    // → 100n

使用严格相等运算符的操作数时,使用构造函数创建的Bigint与常规Bigint的处理方式类似

BigInt(true) === 1n;    // → true
库函数

在撰写本文时,Chrome +67Opera +54完全支持BigInt数据类型。不幸的是,EdgeSafari还没有实现它。Firefox默认不支持BigInt,但是可以在about:config中将javascript.options.bigint 设置为true来开启它,最新支持的情况可在“Can I use”上查看。

不幸的是,转换BigInt是一个极其复杂的过程,这会导致严重的运行时性能损失。直接polyfill BigInt也是不可能的,因为该提议改变了几个现有操作符的行为。目前,更好的选择是使用JSBI库,它是BigInt提案的纯JS实现。

这个库提供了一个与原生BigInt行为完全相同的API。下面是如何使用JSBI:

import JSBI from "./jsbi.mjs";

const b1 = JSBI.BigInt(Number.MAX_SAFE_INTEGER);
const b2 = JSBI.BigInt("10");

const result = JSBI.add(b1, b2);

console.log(String(result));    // → "9007199254741001"

使用JSBI的一个优点是,一旦浏览器支持,就不需要重写代码。 相反,可以使用babel插件自动将JSBI代码编译为原生 BigInt代码。

总结

BigInt是一种新的数据类型,用于当整数值大于Number数据类型支持的范围时。这种数据类型允许我们安全地对大整数执行算术操作,表示高分辨率的时间戳,使用大整数id,等等,而不需要使用库。

重要的是要记住,不能使用NumberBigInt操作数的混合执行算术运算,需要通过显式转换其中的一种类型。 此外,出于兼容性原因,不允许在BigInt上使用一元加号(+)运算符。

交流

干货系列文章汇总如下,觉得不错点个Star,欢迎 加群 互相学习。

https://github.com/qq44924588...

我是小智,公众号「大迁世界」作者,对前端技术保持学习爱好者。我会经常分享自己所学所看的干货,在进阶的路上,共勉!

关注公众号,后台回复福利,即可看到福利,你懂的。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/106151.html

相关文章

  • 如何向 ArrayBuffer 写入 Uint64 数据

    摘要:由于这个原因,在一些需要更精确运算的应用场景中,精度就不够了,例如需要把位数字写入到数组中。但是这又如何在中读写位数据操作中位数据的方案写一个,在项目中引入,以下例子为使用方式与类似使用的得出的结果应该与原生方法保持一致的。 JS 的 Uint53 JS 的 Number 精度只有 「-2^52 ~ 2^52 - 1」,可以通过 Number.MAX_SAFE_INTEGER 查看 J...

    ad6623 评论0 收藏0
  • 每日前端进阶第二题:JS基本数据类型有哪几种?null 是对象吗?基本数据和复杂数据类型有什么区别

    摘要:作者陈大鱼头链接背景最近高级前端工程师刘小夕在上开了个每个工作日布一个前端相关题的,怀着学习的心态我也参与其中,以下为我的回答,如果有不对的地方,非常欢迎各位指出。 作者:陈大鱼头 github: KRISACHAN 链接:github.com/YvetteLau/S… 背景:最近高级前端工程师 刘小夕 在 github 上开了个每个工作日布一个前端相关题的 repo,怀着学习的心态我也参...

    Render 评论0 收藏0
  • ECMASCript 2019可能会有哪些特性?

    摘要:可能不会包括所有的语法提案。事实上,有些提案已经被搁置很多年了。因此,很可能也会在今年月份发布。 译者按: 又过了1年... 原文:Whats New in JavaScript for 2019 译者: Fundebug 为了保证可读性,本文采用意译而非直译。另外,本文版权归原作者所有,翻译仅用于学习。 最近这些年,ECMASCript标准发展节奏非常稳定,每年都会发布新的特...

    tuantuan 评论0 收藏0
  • 精读《Typescript 3.2 新特性》

    摘要:引言发布了几个新特性,主要变化是类型检查更严格,对一些时髦功能拓展了类型支持。精读这次改动意图非常明显,是为了跟上的新语法。基本可以算是对社区的回馈。讨论地址是精读新特性如果你想参与讨论,请点击这里,每周都有新的主题,周末或周一发布。 1 引言 Typescript 3.2 发布了几个新特性,主要变化是类型检查更严格,对 ES6、ES7 一些时髦功能拓展了类型支持。 2 概要 下面挑一...

    cucumber 评论0 收藏0
  • FCC 成都社区·技术周刊 第 12 期

    摘要:详情怎样规避地狱作者先介绍什么是地狱,以及在开发过程中怎样去规避地狱,一时爽性能问题火葬场。详情其他亮点汇总开发者大会已于北京时间月日凌晨在美国山景城正式启幕。 【前端】 1. JavaScript 的新数据类型:BigInt BigInt 是 JavaScript 中的一个新的数字基本(primitive)类型,可以用任意精度表示整数。使用 BigInt 可以安全地存储和操作大整数,...

    fanux 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<