你不知道的 parseInt |多重惊喜

本文涉及的产品
云解析DNS,个人版 1个月
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
简介: 你不知道的 parseInt |多重惊喜

前言


parseInt 用于解析一个字符串并返回指定基数的十进制整数,使用语法 parseInt(string, radix)radix 表示字符串的基数,值为 2 ~ 36


提起 parseInt ,小包脑海中不由自主会浮现两个东西,其一是 parseInt 的截断用法;其二就是烂大街的 ['1', '2', '3'].map(parseInt) 面试题。尤其是后面这个面试题,最开始简直就是魂牵梦萦的噩梦。但这真的是 parseInt 的全部吗?下面和小包一起来探索 parseInt 的重重惊喜吧。


惊喜一: parseInt (0.0000005) === 5 为 true,大大的疑惑?


小小的脑袋,大大的疑惑,parseInt 转换后的数字为什么会是 5 呐,不应该是 0 吗?(注意传入参数为浮点类型,不是字符串)


我们来看一下 MDNparseInt 语法的解释: parseInt 方法接收两个参数待解析值 string,基数 radixstring 参数如果不是字符串,则会调用其 toString 方法转换为字符串。因此遇到非字符串解析值,parseInt 内部会有两部操作:


Step1: 调用 toString 方法


(0.5).toString(); //  '0.5'
(0.05).toString(); //  '0.05'
(0.005).toString(); //  '0.005'
(0.0005).toString(); //  '0.0005'
(0.00005).toString(); //  '0.00005'
(0.000005).toString(); //  '0.000005'
(0.0000005).toString(); //  '5e-7'
复制代码


注意上面的输出,我们可以发现当数字过小时,toString 输出的结果是科学计数法形式。


Step2: 截断操作


引用一段来自 StackOverflow 的解释:

parseInt 只能将字符串的前导部分解释为整数值;它忽略任何不能被解释为整数的代码单元,并且不会有忽略指示。


因此答案只会返回 5 ,其余的 e-7 被忽略。


注意事项:


如果将要解析的值放入字符串中,那么上面这种惊喜就不会出现了:


parseInt("0.0000005"); // 0
parseInt("0.000000005"); // 0
复制代码


从这个惊喜我们可以收获一个警示:尽可能要避免隐式类型转换。


扩展


数字过小时,调用 toString 方法,会返回科学技术法格式表示;数字过大时,同样也会有类似的情况。


parseInt(999999999999999999999) // 1
// (999999999999999999999).toString()
// '1e+21'
复制代码


但小包在测试过程中发现一些临界值,比较奇怪,有兴趣大家可以去探讨一下。


// 10000000000000000
parseInt(9999999999999999)
复制代码


惊喜二:radix 默认值是 10 吗,何种情况返回值是 NaN?


下面我们就几种情况对这个惊喜进行分析:


2.1 radix 值为 undefined、0 或未指定的


radix 值为 undefined、0 或未指定的,那 JavaScript 会如何处理这种情况:


  1. 如果输入的 string0x0X 开头,那么 radix 会被假定为 16 ,字符串的其他部分按照十六进制来解析。
  2. 如果输入的 string0 开头,ES5 规定使用十进制,但并非所有的浏览器都支持,因此使用 parseInt 时,需要指定 radix
  3. 如果输入的 string 以其他任何值开头,radix 值为 10


我们用 google 浏览器体验一下上述规则。


parseInt("0x16"); // 22
parseInt("0888"); // 888
parseInt("123px"); // 123
复制代码


2.2 radix 值小于 2 或 大于 36


radix 参数的值为 2 ~ 36,当 radix 小于 2 或 大于 36(不包含 0),返回值为 NaN


parseInt("123px", 1); // NaN
parseInt("123px", 38); // NaN
parseInt("123px", -1); // NaN
复制代码


2.3 待转换字符串中,所有的可转换数字都不小于 radix 值


举个栗子: 例如 radix 值为 2 (二进制),而待转换字符串为 '3456',二进制内只有 0、1 是基本算符,因此字符串 '3456' 无法转换成二进制,返回值为 NaN


parseInt("3456", 2); // NaN
parseInt("45px", 3); // NaN
复制代码


2.4 总结


学习完上面几种情况,我们就可以来回答惊喜二的问题了。


  1. radix 默认值是 10 吗?答案: 不是radix 还会考虑 string 参数,如果 string0x(0X) 开头,radix16;若以 0 开头,不同的浏览器有可能有不同的值;其余情况 radix10
  2. 何种情况返回值是 NaN
  • radix 值小于 2 或 大于 36
  • 待转换字符串中,所有的可转换数字都不小于 radix 值(例如 parseInt('345', 2))
  • 第一个非空格字符不能转换为数字(例如 parseInt('a123'))


惊喜三:radix 参数引出的面试题


3.1 ['1', '2', '3'].map(parseInt)


map 函数对数组的每个元素执行回调函数,并返回含有运算结果的新数组。


// val 为数组值
// index 为当前数组索引
// _arr 为当前数组
arr.map((val, index, _arr) => {});
复制代码


因此 ['1', '2', '3'].map(parseInt) 就等同于下面的代码:


[parseInt("1", 0), parseInt("2", 1), parseInt("3", 2)];
复制代码


  1. parseInt("1", 0)符合 2.1radix0,且 string 以字符 1 开始,radix 值为 10,值为 1
  2. parseInt("2", 1)符合 2.2radix 小于 2,返回 NaN
  3. parseInt("3", 2)符合 2.3,待转换字符串中,所有的可转换数字大于 radix 值,返回 NaN


因此该面试题的答案为 [1, NaN, NaN]


3.2 ['10', '10', '10', '10'].map(parseInt)


有了上面的基础,这个题目就好理解了,我们先将这个方法等价转化一下:


[parseInt("10", 0), parseInt("10", 1), parseInt("10", 2), parseInt("10", 3)];
复制代码


相当于将 '10' 分别转化为十进制,一进制,二进制,三进制,因此该面试题的结果是 [10, NaN, 2, 3]


惊喜四:parseInt 的旁支末节


parseInt 方法除了上面提到的惊喜外,还有一些旁支末节,也需要注意一下:


  1. parseInt 允许前导和后置空格,在进行转换前,会首先删除字符串的前导和后置空格。
// 允许前导和后置空格
parseInt("  123 "); // 123
// 中间出现的空格会被当做截断符
parseInt("123 456 "); // 123
复制代码


  1. parseInt 可以理解正负号


parseInt("+123"); // 123
parseInt("-123"); // -123
// 只能理解第一个正负号,第二个非数字字符,因此返回 NaN
parseInt("+-123"); // NaN
复制代码


  1. 使用 parseInt 转换 BigInt 会损失精度


parseIntBigInt 转换为 Number,并在这个过程中失去了精度。这是因为拖尾的非数字值,包括 "n",会被丢弃。


let bigInt = 111111111111111111111111n;
parseInt(bigInt); // 1.1111111111111111e+23
let bigInt2 = 11n;
parseInt(bigInt2); // 11
复制代码


博文仓库


传送门: 战场小包的博客库


别忘了给小包点个 🌟。




相关文章
|
10月前
|
C语言
透过猜数字的小游戏来重新认识和学习随机数(rand())和时间函数(time(NULL))
透过猜数字的小游戏来重新认识和学习随机数(rand())和时间函数(time(NULL))
|
JavaScript 测试技术
【若川视野 x源码共读】第33期 | arrify 转数组 Convert a value to an array
mac: 在github代码仓库页面通过快捷键 command + k,再在文本框中输入 ">",即可查看到在线打开的命令行
82 0
竟然有一半的人不知道 for 与 foreach 的区别???
竟然有一半的人不知道 for 与 foreach 的区别???
101 0
|
测试技术
【类型挑战】深度 Readonly,难度⭐️⭐️
【类型挑战】深度 Readonly,难度⭐️⭐️
287 0
【类型挑战】深度 Readonly,难度⭐️⭐️
|
测试技术
【类型挑战】Readonly 2,难度⭐️⭐️
【类型挑战】Readonly 2,难度⭐️⭐️
135 0
【类型挑战】Readonly 2,难度⭐️⭐️
|
JavaScript 测试技术
【类型挑战】Parameters,难度⭐️
【类型挑战】Parameters,难度⭐️
112 0
【类型挑战】Parameters,难度⭐️
|
测试技术 索引
【类型挑战】实现 Omit,难度⭐️⭐️
【类型挑战】实现 Omit,难度⭐️⭐️
217 0
【类型挑战】实现 Omit,难度⭐️⭐️
|
测试技术 API
【类型挑战】元组转联合,难度⭐️⭐️
【类型挑战】元组转联合,难度⭐️⭐️
155 0
【类型挑战】元组转联合,难度⭐️⭐️
|
测试技术
【类型挑战】Trim Left,难度⭐️⭐️
【类型挑战】Trim Left,难度⭐️⭐️
214 0
|
测试技术
【类型挑战】Trim Right,难度⭐️⭐️
【类型挑战】Trim Right,难度⭐️⭐️
120 0