JavaScript:['1','2','3'].map(parseInt)问题解析
2015-12-11 11:18
876 查看
最近碰到了[‘1’,’2’,’3’].map(parseInt)这种看似不起眼陷阱却极大的问题。
这乍一看,感觉应该会输出[1,2,3]。但是,实际上并不是我们想的这样。你可以现在打开console,看看输出的结果。
出乎意料结果竟然是[1,NaN,NaN].
至于为什么是这样,下面一步一步的解释。
函数返回的结果是123 ,并赋值给变量n。这里应该没什么问题。
当然,如果传入pasreInt()参数并不能被解析成数值表达式,那么函数执行后将返回 NaN。NaN的含义就是Not a Number(不是一个数值)。
此时m的值应该就是NaN。
很好理解,最后的结果的应该是[2,3,4].这种调用应该是很常见的。但是有时将已经存在的函数作为参数传入map是无效的啊,比如parseInt.
清楚了parsenInt和map的基本用法之后,再来看看比较容易忽视的问题。
返回的结果是65535,然而
返回的结果是NaN,因为“ffff”并不能解析成一个八进制的数值。如果第二个参数省略了或者是0,parseInt默认为是10进制 所以
都会返回数值12。
现在看看map
的定义。map指定传入的函数参数作为callbackfn.规范里指出:“callbackfn调用时需要传入三个参数:元素的值,元素的索引和正在被遍历的对象”。仔细体会一下,原本我们以为对parseInt的三次调用是这样:
然而实际上是这样调用的:
这里theArray 就是原始数组[‘1’,’2’,’3’]。
JS函数一般会自动忽视多余的参数,parseInt仅仅需要两个参数,所以我们并不需要担心这个theArray参数对parseInt的影响。
重点来了,第二个参数是如何影响parseInt的
在第一次调用时,parseInt的第二个参数是0,上面已经说了,所以第一调用
返回1.
第二次调用第二个参数是1,也是说1作为数值的基础。规范里说的很清楚了,如果基础是非0或者小于2,函数都不会查询字符串直接返回NaN。
第三次调用时,2作为基数。这就意味着字符串将被解析成字节数,也就是仅仅包含数值0和1。parseInt的规范第十一步指出,它仅尝试分析第一个字符的左侧,这个字符还不是要求基数的有效数字。这个字符串的第一个字符是“3”,它并不是基础基数2的一个有效数字。所以这个子字符串将被解析为空。第十二步说了:如果子字符串被解析成空了,函数将返回为NaN。
所以这里的结果就应该是[1,NaN,NaN].
这里问题所在就是容易忽视parseInt是需要两个参数的。map中有三个参数。所以这里结合起来,就导致了上面问题。
换个方式写:
这样就不会出错。
当然,我们也可以写:
参考:http://www.wirfs-brock.com/allen/posts/166
这乍一看,感觉应该会输出[1,2,3]。但是,实际上并不是我们想的这样。你可以现在打开console,看看输出的结果。
出乎意料结果竟然是[1,NaN,NaN].
至于为什么是这样,下面一步一步的解释。
parseInt()
parseInt是JS的一个内置函数,它可以将字符创解析成一个数值表达式并将该数值返回。调用的时候如下:[code]var n = parseInt('123')
函数返回的结果是123 ,并赋值给变量n。这里应该没什么问题。
当然,如果传入pasreInt()参数并不能被解析成数值表达式,那么函数执行后将返回 NaN。NaN的含义就是Not a Number(不是一个数值)。
[code]var m = parseInt('xyz)
此时m的值应该就是NaN。
Array.prototype.map
map 是ECMAScript 5 的一个内置数值方法.map把函数作为它的参数。map遍历数组中所有的元素,并且为每个元素调用一次这个传入map中的函数,当前元素作为参数传入该函数。map函数调用完毕之后将返回的结果存入一个新数组中。看下面这个例子:[code][1,2,3].map(function(value){ return value+1 })
很好理解,最后的结果的应该是[2,3,4].这种调用应该是很常见的。但是有时将已经存在的函数作为参数传入map是无效的啊,比如parseInt.
清楚了parsenInt和map的基本用法之后,再来看看比较容易忽视的问题。
解决方法
现在来看看ECMAScript 5 中parseInt 的用法。有会发现它可以接受两个参数。第一个参数是要被解析的字符串,第二个参数是要解析成数值的基础。所以,parseInt('ffff',16)
返回的结果是65535,然而
[code]parseInt('ffff',8)
返回的结果是NaN,因为“ffff”并不能解析成一个八进制的数值。如果第二个参数省略了或者是0,parseInt默认为是10进制 所以
[code]parseInt("12",10) ; parseInt("12") ; parseInt("12",0) ;
都会返回数值12。
现在看看map
的定义。map指定传入的函数参数作为callbackfn.规范里指出:“callbackfn调用时需要传入三个参数:元素的值,元素的索引和正在被遍历的对象”。仔细体会一下,原本我们以为对parseInt的三次调用是这样:
[code]parseInt('1') parseInt('2') parseInt('3')
然而实际上是这样调用的:
[code]parseInt('1',0,theArray); parseInt('2',1,theArray); parseInt('3',2,theArray);
这里theArray 就是原始数组[‘1’,’2’,’3’]。
JS函数一般会自动忽视多余的参数,parseInt仅仅需要两个参数,所以我们并不需要担心这个theArray参数对parseInt的影响。
重点来了,第二个参数是如何影响parseInt的
在第一次调用时,parseInt的第二个参数是0,上面已经说了,所以第一调用
parseInt('1',0)
返回1.
第二次调用第二个参数是1,也是说1作为数值的基础。规范里说的很清楚了,如果基础是非0或者小于2,函数都不会查询字符串直接返回NaN。
第三次调用时,2作为基数。这就意味着字符串将被解析成字节数,也就是仅仅包含数值0和1。parseInt的规范第十一步指出,它仅尝试分析第一个字符的左侧,这个字符还不是要求基数的有效数字。这个字符串的第一个字符是“3”,它并不是基础基数2的一个有效数字。所以这个子字符串将被解析为空。第十二步说了:如果子字符串被解析成空了,函数将返回为NaN。
所以这里的结果就应该是[1,NaN,NaN].
这里问题所在就是容易忽视parseInt是需要两个参数的。map中有三个参数。所以这里结合起来,就导致了上面问题。
换个方式写:
[code]['1','2','3'].map(function(value){ return parseInt(value) })
这样就不会出错。
当然,我们也可以写:
[code]['1','2','3'].map(Number)
参考:http://www.wirfs-brock.com/allen/posts/166
相关文章推荐
- js之事件冒泡和事件捕获
- js获取一个对象的所以属性和值
- extjs 事件参数,不加,就要使用绝对引用
- 如果把去掉数组里面重复的项
- javascript初学者入门小例子
- 在JSP中如何使用JSTL(EL表达式)格式化日期
- shp与json互转
- JSON使用DateFormatHandling 序列化与反序列化日期设置
- JavaScript学习笔记之——js在页面中的位置、语句、符号、注释
- 表单中有一个搜索框,有两个radio条件选择,选中第一个时点击提交按钮时就跳转到zs_search.jsp搜索页面,
- Javascript 字符串常用操作方法
- 把DataTable转换为泛型List<T>或是JSON
- jetty发布项目jsp不编译按文本输出问题
- Extjs提交的Json里中文乱码
- JS判断是否是IE浏览器仅仅需要7bytes!
- 页面缓存js问题解决
- 页面缓存js问题解决
- js 时间
- Javascript中改变this指针的指向的三种方法
- js获取手机联网状态