带你秒懂ParseInt

337 阅读3分钟

写在前面

我们都知道parseInt可以将字符串转换成数字。那它和Number转换有什么区别吗?我们从一组例子来看:

var a = '42'
var b = '42px'

Number(a)  //42
parseInt(a)  //42

Number(b)  //NaN
parseInt(b)  //42

解析允许字符串中含有非数字字符,解析从左到右的顺序,如果遇到非数字字符就停止。而强制类型转换不允许出现非数字字符,否则会失败,并返回NaN

看看定义

parseInt(string, radix): 解析一个字符串并返回指定基数的十进制整数。
radix 是 2-36 之间的整数,表示被解析字符串的基数。 假如指定 0 或未指定,基数将会根据字符串的值进行推算

需要注意的返回NaN的情况:

  1. radix > 36或者 radix < 2
  2. 第一个非空格字符不能转换为数字

特殊情况:

  1. 如果输入的 string 以 0x 或 0X(一个 0,后面是小写或大写的 X)开头,那么 radix 被假定为 16,字符串的其余部分被当做十六进制数去解析
  2. 如果输入的 string 以 "0"(0)开头,radix 被假定为 8(八进制)或 10(十进制)。具体选择哪一个 radix 取决于实现。ECMAScript 5 澄清了应该使用 10 (十进制),但不是所有的浏览器都支持。因此,在使用 parseInt 时,一定要指定一个 radix
  3. 如果输入的 string 以任何其他值开头,radix 是 10 (十进制)
  4. 如果字符串里有空格,parseInt允许前导和尾随空格

来看看正常的用法

parseInt('123', 5)  // 1 * 5^2 + 2 * 5 + 3 * 5^0 = 38
parseInt("0xF", 16) // 15
parseInt("F", 16) // 15
parseInt("17", 8) // 15
parseInt("015", 10)   // 15
parseInt(15.99, 10) //15
parseInt("15,123", 10) //15
parseInt("1111", 2) // 15
parseInt("15 * 3", 10) // 15
parseInt("15e2", 10) // 15

踩坑一:如果parseInt的参数不是字符串,则会先转为字符串再转换

parseInt(021, 8)
parseInt(015, 8)

先自己算算看,这两个答案多少?
答案是:17, 11。
有没有被这个答案惊到呢。这里面有个坑:如果parseInt的参数不是字符串,则会先转为字符串再转换,所以对上述的例子来说, 021会首先转换成string ---> '17', 所以parseInt(021, 8) 等价于 parseInt('17', 8),即: 1 * 8 + 7 * 8^0 = 15。同理, parseInt(015, 8) 等价于parseInt('13', 8) = 11

踩坑二:科学计数法

parseInt(0.000008) // 0
parseInt(0.0000008) //8 (8e-7)
parseInt(800000000000000000000) // 800000000000000000000
parseInt(8000000000000000000000) // 8 (8e21)

当小数点后0的个数小于或者等于5个0时,以字面量的形式表示,当大于5个0时,用科学计数法表示;而当小数点前的位数小于或者等于21时,采用的是字面量,当大于21位时,用科学计数法表示。

踩坑三: 截断操作

parseInt('42px') // 42
parseInt(false, 16) //250

这里就回到了文章最开始提到的例子啦~ 为啥parseInt('42px'),里面有无效数字字符还是可以转换成数字,就是parseInt它有个截断操作,当它在解析的过程中遇到不是有效的数字字符,它的解析就会就此停止。因此parseInt('42px'),当它解析过程中遇到p时就停止了。而对于另一个例子来说,它radix的值为16,按照一个16进制来解析,只能解析fal已经超出16进制的表示数,因此停止,parseInt(false, 16)等价于parseInt('fa', 16) ==> 15 * 16 ^ 1 + 10 * 16^0 = 250

踩坑四: 特殊值

parseInt('34', 2)  // NaN, 字符超出2进制的表示范围
parseInt('103', 2)  // 2 = 1 * 2^1 + 0 * 2^0 ,    3超出范围,解析停止
parseInt(011, 2) // NaN 

这里讲一下第3个例子,其实前面踩坑一中提到了,对于011,parseInt会先把它转换成字符串,而011是个八进制的表示数,所以,在变成字符串后变成了'9',即parseInt(011, 2)等价于parseInt('9', 2),而9是超过了2进制的表示范围的 ==> NaN

parseInt(1/0, 19)  // 18

这题我自己捋了一下的:
首先1/0,这个值肯定是个无穷大,js会把这个值toString的时候变成Infinity,所以呢,这题就变成了:parseInt('Infinity', 19) ,对于19进制的数来说,表示范围为: 0~9,a~i。解析的时候只能解析到开头的I,对基数19的数来说,I即为 18

踩坑五: 面试题

听说有个面试题比较坑,也整理了进来:
[1,2,3].map(parseInt())
说这个题之前,要先回忆下map,对这一题来说,map是略写了而已,我们把这个题写全就会变得很清晰:

[1,2,3].map(parseInt) ==> [1,2,3].map((item, index) => { parseInt(item, index)) })

=> 
       parseInt(1, 0) // 1
       parseInt(2, 1) // NaN
       parseInt(3, 2) // NaN

结言

结束了,hhh,对面试还是有点用的,大家可以了解一下。