刷算法题遇到的新数据类型-—-BigInt

今天在LeetCode做的一道关于 “加一” 的算法题,题目如下

`给定一个由整数组成的非空数组所表示的非负整数,在该数的基础上加一。
最高位数字存放在数组的首位, 数组中每个元素只存储一个数字。
你可以假设除了整数 0 之外,这个整数不会以零开头。

示例 1:
输入: [1,2,3]
输出: [1,2,4]
解释: 输入数组表示数字 123。

示例 2:
输入: [4,3,2,1]
输出: [4,3,2,2]
解释: 输入数组表示数字 4321。`

我的代码是这样的

const plusOne = function(digits) {
    for(let i = digits.length - 1;i >= 0;i--){
        if(digits[i] == 9){
            digits[i] = 0;
        } else {
            digits[i]++;
            return digits;
        }
    }
    // 为9的情况
    digits.unshift(1);
    return digits;
};

后面在题解区看到一位大神的代码只有一行

const plusOne = (digits) => {
  return (BigInt(digits.join('')) + 1n).toString().split('');
};

这个方法很巧妙,将数组转换成字符串,再转换成数字进行加一计算,最后再转回数组。我们平时将字符串强制转成数字用的是Number(), 这里的BigInt是什么呢?接下来我们详细了解下BigInt。

一、Number 类型的局限性

JavaScript 内部只有一种数字类型Number,也就是说,JavaScript 语言的底层根本没有整数,所有数字都是以IEEE-754标准格式64位浮点数形式储存,1与1.0是相同的。因为有些小数以二进制表示位数是无穷的。JavaScript会把超出53位之后的二进制舍弃,所以涉及小数的比较和运算要特别小心。 具体介绍可查看我的另外一篇文章:解决JS浮点数运算结果不精确的Bug

这意味着在JavaScript中,Number类型只能安全地表示-9007199254740991 (-(2^53-1)) 和9007199254740991(2^53-1)之间的整数,任何超出此范围的整数值都可能被自动四舍五入丢失精度。如下,可以看到 max + 1 与 max + 2 的值相同,这显然是不对的。

let max = Number.MAX_SAFE_INTEGER
console.log(max) // 9007199254740991
console.log(max + 1) // 9007199254740992
console.log(max + 2) // 9007199254740992

二、解决方案

在没有 BigInt 的时候,如果想要使用大整型,一些JS开发人员使用字符串类型表示大整数。 例如,Twitter API 在使用 JSON 进行响应时会向对象添加字符串版本的 ID。 还可以借助类似 BigInt 功能的第三方库。例如 bignumber.js。这有可能会影响 JavaScript 程序的效率,比如加载时间、解析时间、编译时间,以及运行时的效率。

三、BigInt介绍

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

四、定义BigInt

【4.1】在整数的末尾追加n

// 十进制
console.log(10n);      // 10n   

// 二进制
console.log(0b10n);    // 2n    
console.log(0B10n);    // 2n

// 八进制
console.log(0o5n);     // 5n    
console.log(0O5n);     // 5n

// 十六进制
console.log(0xFn);     // 15n   
console.log(0XFn);     // 15n

【4.2】调用 BigInt() 构造函数

// 十进制
console.log(BigInt('10');      // 10n   

// 二进制
console.log(BigInt('0b10'));    // 2n   
console.log(BigInt('0B10'));    // 2n

// 八进制
console.log(BigInt('0o5'));     // 5n   
console.log(BigInt('0O5'));     // 5n

// 十六进制
console.log(BigInt('0xF'));     // 15n  
console.log(BigInt('0XF'));     // 15n

五、BigInt类型

既然 BigInt 是一个新的原始类型,那么它就可以使用 typeof 检测出自己的类。请记住,不能使用严格相等运算符将 BigInt 与常规数字进行比较,因为它们的类型不同:

typeof(10)  // number
typeof(10n) // bigint

10n === 10  // false
10n == 10   // true

六、BigInt运算

BigInt 支持绝大部分常用运算符:+,-,,/,%,*。 除 >>>(无符号右移)之外的位运算符也可以支持:|,&,<<,>>,^,因为BigInt都是有符号的。为了兼容 asm.js ,BigInt不支持单目 (+) 运算符。另外就是不能混合使用 BigInt与 Number 计算,否则会抛出异常

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
10n + 10;     // TypeError: Cannot mix BigInt and other types

// 混合运算需转换
BigInt(10) + 10n; // 20n
Number(10 ) + 10; // 20

七、BigInt与Number的比较

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

new Number(1) // √
new BigInt(1) // ×

【7.2】****当没有参数时,Number返回0,BigInt抛出TypeError

Number() // 0
BigInt() // TypeError

【7.3】当参数为非数字时,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

【7.4】两者对 -0 的处理也不同

Number(-0) === -0
BigInt(-0) === -0n

【7.4】对于布尔值,两者都会把 true 转换为 1,把 false 转换为 0

Number(true)  // 1
Number(false) // 0

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

【7.5】对于浮点数,BigInt抛出 RangeError 异常

BigInt(4.00000001) // RangeError

【7.6】****对于 NaN 和正负无穷,BigInt抛出RangeError异常

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

7.7当使用 BigInt 时,带小数的运算会被取整

let a = 5 / 2;    // 2.5
let b = 5n / 2n;  // 2n

【7.8】Number 和 BigInt 可以进行比较,两者也可以混在一个数组内并排序。

1n < 2   // true
2n > 1   // true
2n > 2   // false
2n >= 2  // true

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

八、实例方法

【8.1】BigInt.prototype.toLocaleString() : **返回此数字的 language-sensitive 形式的字符串 查看案例

【8.2】BigInt.prototype.toString() : **返回以指定基数(base)表示指定数字的字符串 查看案例

【8.3】BigInt.prototype.valueOf(): **返回指定对象的基元值 查看案例

九、注意

1、由于在 Number 与 BigInt 之间进行转换会损失精度,因而建议仅在值可能大于2^53 时使用 BigInt 类型,并且不在两种类型之间进行相互转换。

2、对任何 BigInt 值使用 JSON.stringify() 都会引发 TypeError,因为默认情况下 BigInt 值不会在 JSON 中序列化。

3、如果你确定你的页面只跑在最新的 Chrome 中,那么现在就可以大胆的使用 BigInt 了,更优雅高效的处理大数据。若在其他浏览器中需要支持,可以使用 JSBI 这个库,日后甩掉它的姿势也十分优雅

文章每周持续更新,可以微信搜索「 前端大集锦 」第一时间阅读,回复【视频】【书籍】领取200G视频资料和30本PDF书籍资料

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,254评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,875评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,682评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,896评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,015评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,152评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,208评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,962评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,388评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,700评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,867评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,551评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,186评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,901评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,142评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,689评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,757评论 2 351