本文深入解析JavaScript中parseInt函数的使用细节,重点讲解其两个参数的作用及默认基数推算规则。通过分析[1,2,3].map(parseInt)的经典案例,揭示回调函数参数传递导致的精度丢失问题,并提供避免NaN返回的最佳实践建议。
文章开始
首先来看一道经典面试题:['1','2','3'].map(parseInt)
初看之下,很多人会直接给出答案:[1,2,3]
但在控制台实际运行后,结果却是:['1',NaN,NaN]
为什么会这样?我对map函数已经很熟悉了,问题究竟出在哪里?大概率是parseInt这个函数的特性导致的。
回顾一下map函数的机制
map()方法会创建一个新数组,其元素是原数组中每个元素调用一次提供的回调函数后的返回值。该方法主要接收两个参数:一个是回调函数,另一个是指定回调函数内部this指向的对象。
1. 第一个参数:回调函数
var newArr = [1, 2, 3].map((item, index, arr) => {
console.log(item, index, arr)
return item * 2
})
/*
1 0 [ 1, 2, 3 ]
2 1 [ 1, 2, 3 ]
3 2 [ 1, 2, 3 ]
*/
console.log(newArr) // [ 2, 4, 6 ]
回调函数的三个参数依次为:1.当前正在处理的元素;2.当前元素的索引;3.调用map的数组;
2. 第二个参数:指定this
var obj = { name: 'obj对象' }
var newArr = [1, 2, 3].map(function (item, index, arr) {
return item * 2 + this.name
}, obj)
console.log(newArr) // [ '2obj对象', '4obj对象', '6obj对象' ]
这里需要特别注意,此处不能使用箭头函数,因为箭头函数没有自己的this绑定,其内部的this继承自定义时外层作用域的this。
学习parseInt函数
parseInt(string, radix)用于解析一个字符串,并返回指定基数的十进制整数。其中radix是一个2到36之间的整数,代表被解析字符串的基数。
如何理解这两个参数:
- 将字符串A转换为数字B;
- 第一个参数:需要被转换的字符串A;
- 第二个参数:表示进制的基数(通俗来说,就是告诉函数将字符串A当作多少进制来处理)。
正常情况下的使用示例:
console.log(parseInt('10')) // 10
console.log(parseInt('10a')) // 10
console.log(parseInt('111', 2)) // 7
console.log(parseInt('A12', 16)) // 2578
注意事项:
对于parseInt的第一个参数,如果传入的不是字符串,系统会将其转换为字符串(使用ToString抽象操作)。同时,字符串开头的空白字符会被自动忽略。
对于parseInt的第二个参数,其取值范围是2到36的整数,表示进制的基数。例如,指定16表示被解析的值是十六进制数。如果传入的值超出这个范围,函数将返回NaN。假如指定0或未指定该参数,基数将会根据字符串的内容进行推算。需要注意的是,推算的结果并不总是默认为10!文章后文的描述解释了当参数radix不传时该函数的具体行为。
1. 如果第一个参数不是字符串,它会被转换为字符串,且开头的空白符会被忽略。
console.log(parseInt(10)) // 10
console.log(parseInt(' 10')) // 10
console.log(parseInt(' 11 22')) // 11 /* 如果字符之间有空格,读取第一个 */
2. 第二个参数的取值范围必须是2到36的整数,如果超出这个范围,将返回NaN。
console.log(parseInt('10', 1)) // NaN
console.log(parseInt('10', 2)) // 2
console.log(parseInt('10', 36)) // 36
console.log(parseInt('10', 37)) // NaN
3. 如果第二个参数指定为0或未指定,基数将会根据字符串的值进行推算。
console.log(parseInt('10')) // 10
console.log(parseInt('010')) // 10 /* 某些浏览器这里会解读成 8进制 */
console.log(parseInt('ox10')) // NaN
/* 第二个参数如果是字符串,会被尝试读取数字 */
console.log(parseInt('10', '36')) // 36
/* **我实践的结果:** 第二个参数如果是字符串,会被尝试读取数字,无法读取,默认基数将会根据字符串的值进行推算*/
console.log(parseInt('10', '7tamato')) // 10
console.log(parseInt('10', 'tamato7')) // 10
console.log(parseInt('0x10', 'tamato7')) // 16
估算的方式如下:
- 如果输入的string以0x或0X(即数字0后跟小写或大写的X)开头,那么radix被假定为16,字符串的其余部分被当作十六进制数去解析。
- 如果输入的string以“0”(数字0)开头,radix被假定为8(八进制)或10(十进制)。具体选择哪一个radix取决于浏览器的实现。ECMAScript 5澄清了应该使用10(十进制),但并非所有浏览器都支持这一标准。因此,在使用parseInt时,强烈建议显式指定一个radix。
- 如果输入的string以任何其他值开头,radix是10(十进制)。
4. 如果解析的字符串中包含的数字超过当前基数,返回NaN
console.log(parseInt('3', 2)) // NaN
console.log(parseInt('4', 3)) // NaN
console.log(parseInt('1324', 3)) // NaN
5. 小数点后超过7位的情况
console.log(parseInt(0.000005)) // 0
console.log(parseInt(0.0000005)) // 5
/* 原因是 0.0000005 不是字符串,会被toString() => 5e-7 */
console.log((0.0000005).toString()) // 5e-7
回到最初的问题
['1','2','3'].map(parseInt)
可以这样理解:
parseInt('1',0,['1','2','3'])
parseInt('2',1,['1','2','3'])
parseInt('3',2,['1','2','3'])
- parseInt没有第三个参数,所以可以忽略。
- 基数为0 => 默认10进制
- 解析的字符串包含的数字超过基数,返回NaN
所以答案:[1,NaN,NaN]
总结:
由于parseInt第二个参数的推算规则并不稳定,所以建议在使用parseInt时,始终显式添加第二个参数。
再梳理一下解析规则:
- 第一个参数默认为字符串类型,如果不是字符串类型,会被
toString;如果字符串无法解析,直接返回NaN;- 第二个参数指定为0或未指定,会根据第一个参数的格式进行推断。基数的取值范围为2-36;如果基数超出范围,返回NaN;
来都来了
既然来了,顺便看一下和parseInt比较相似的parseFloat,parseFloat比较简单,它只有一个参数,就是需要解析的字符串。
对于BigInt类型的数据,使用parseInt和parseFloat转换BigInt类型的数据,都会存在精度丢失的情况,需要注意这一点。
文章结束
其实这道题目就是考察,对parseInt方法的熟悉程度。
总结
到此这篇关于Js中parseInt的使用及注意事项的文章就介绍到这了,更多相关Js parseInt使用内容请搜索本站以前的文章或继续浏览下面的相关文章希望大家以后多多支持本站!