第 2 题:['1', '2', '3'].map(parseInt) what & why ?
YuYuBei opened this issue · 117 comments
第一眼看到这个题目的时候,脑海跳出的答案是 [1, 2, 3],但是真正的答案是[1, NaN, NaN]。
- 首先让我们回顾一下,map函数的第一个参数callback:
var new_array = arr.map(function callback(currentValue[, index[, array]]) { // Return element for new_array }[, thisArg])
这个callback一共可以接收三个参数,其中第一个参数代表当前被处理的元素,而第二个参数代表该元素的索引。
-
而parseInt则是用来解析字符串的,使字符串成为指定基数的整数。
parseInt(string, radix)
接收两个参数,第一个表示被处理的值(字符串),第二个表示为解析时的基数。 -
了解这两个函数后,我们可以模拟一下运行情况
- parseInt('1', 0) //radix为0时,且string参数不以“0x”和“0”开头时,按照10为基数处理。这个时候返回1
- parseInt('2', 1) //基数为1(1进制)表示的数中,最大值小于2,所以无法解析,返回NaN
- parseInt('3', 2) //基数为2(2进制)表示的数中,最大值小于3,所以无法解析,返回NaN
-
map函数返回的是一个数组,所以最后结果为[1, NaN, NaN]
-
最后附上MDN上对于这两个函数的链接,具体参数大家可以到里面看
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/parseInt
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/map
parseInt 基数是一个介于2和36之间的整数 可能第二点这个说法不太准确
在30-seconds-of-code看到一个这个题的变形,分享一下
let unary = fn => val => fn(val)
let parse = unary(parseInt)
console.log(['1.1', '2', '0.3'].map(parse))
我开始也这么理解:第二个参数需要的范围是2~36之间,如果小于 2 或者大于 36,则 parseInt() 将返回 NaN。但是parseInt(5,4),第二个参数在[2,36]之间,但是结果依旧返回NaN啊。
所以后俩返回NaN,我们是不是又两种角度可以理解呢?
这是今天在 Advanced-Frontend组织 看到一个比较有意思的题目。
主要是讲JS的映射与解析
早在 2013年, 加里·伯恩哈德就在微博上发布了以下代码段:
['10','10','10','10','10'].map(parseInt);
// [10, NaN, 2, 3, 4]
parseInt
parseInt()
函数解析一个字符串参数,并返回一个指定基数的整数 (数学系统的基础)。
const intValue = parseInt(string[, radix]);
string
要被解析的值。如果参数不是一个字符串,则将其转换为字符串(使用 ToString 抽象操作)。字符串开头的空白符将会被忽略。
radix
一个介于2和36之间的整数(数学系统的基础),表示上述字符串的基数。默认为10。
返回值
返回一个整数或NaN
parseInt(100); // 100
parseInt(100, 10); // 100
parseInt(100, 2); // 4 -> converts 100 in base 2 to base 10
注意:
在radix
为 undefined,或者radix
为 0 或者没有指定的情况下,JavaScript 作如下处理:
- 如果字符串 string 以"0x"或者"0X"开头, 则基数是16 (16进制).
- 如果字符串 string 以"0"开头, 基数是8(八进制)或者10(十进制),那么具体是哪个基数由实现环境决定。ECMAScript 5 规定使用10,但是并不是所有的浏览器都遵循这个规定。因此,永远都要明确给出radix参数的值。
- 如果字符串 string 以其它任何值开头,则基数是10 (十进制)。
更多详见parseInt | MDN
map
map()
方法创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果。
var new_array = arr.map(function callback(currentValue[,index[, array]]) {
// Return element for new_array
}[, thisArg])
可以看到callback
回调函数需要三个参数, 我们通常只使用第一个参数 (其他两个参数是可选的)。
currentValue
是callback 数组中正在处理的当前元素。
index
可选, 是callback 数组中正在处理的当前元素的索引。
array
可选, 是callback map 方法被调用的数组。
另外还有thisArg
可选, 执行 callback 函数时使用的this 值。
const arr = [1, 2, 3];
arr.map((num) => num + 1); // [2, 3, 4]
更多详见Array.prototype.map() | MDN
回到真实的事例上
回到我们真实的事例上
['1', '2', '3'].map(parseInt)
对于每个迭代map
, parseInt()
传递两个参数: 字符串和基数。
所以实际执行的的代码是:
['1', '2', '3'].map((item, index) => {
return parseInt(item, index)
})
即返回的值分别为:
parseInt('1', 0) // 1
parseInt('2', 1) // NaN
parseInt('3', 2) // NaN, 3 不是二进制
所以:
['1', '2', '3'].map(parseInt)
// 1, NaN, NaN
由此,加里·伯恩哈德例子也就很好解释了,这里不再赘述
['10','10','10','10','10'].map(parseInt);
// [10, NaN, 2, 3, 4]
如何在现实世界中做到这一点
如果您实际上想要循环访问字符串数组, 该怎么办? map()
然后把它换成数字?使用编号!
['10','10','10','10','10'].map(Number);
// [10, 10, 10, 10, 10]
parseInt(string, radix)
这道题的关键点在于parseInt的返回值类型,MDN中说返回值类型为10进制,具体是把string所对应的值当做radix对应的进制看待,然后转换成相应的10进制值。
所以在parseInt('3', 2) 中,'3'在2进制中是一个非法的值,2进制中只能存在0和1,所以最后返回了NAN
parseInt(string, radix),radix在 (2, 8)的时候,Number(string) < radix。
我开始也这么理解:第二个参数需要的范围是2~36之间,如果小于 2 或者大于 36,则 parseInt() 将返回 NaN。但是parseInt(5,4),第二个参数在[2,36]之间,但是结果依旧返回NaN啊。
所以后俩返回NaN,我们是不是又两种角度可以理解呢?
4进制最大数是3,5大于3,所以NaN。
ratio 值为 (2, 8)的时候,parseInt的第一个参数必须小于ratio
我开始也这么理解:第二个参数需要的范围是2~36之间,如果小于 2 或者大于 36,则 parseInt() 将返回 NaN。但是parseInt(5,4),第二个参数在[2,36]之间,但是结果依旧返回NaN啊。
所以后俩返回NaN,我们是不是又两种角度可以理解呢?
第二个参数是处于2~36没错,但是第二个参数代表解析的进制数,在四进制里面是不可能会出现5这个数字的,所以返回的就是NaN,要想转成5的话应该是parseInt('11', 4)结果就是5
string | 必需。要被解析的字符串。 |
---|---|
radix | 可选。表示要解析的数字的基数。该值介于 2 ~ 36 之间。如果省略该参数或其值为 0,则数字将以 10 为基础来解析。如果它以 “0x” 或 “0X” 开头,将以 16 为基数。如果该参数小于 2 或者大于 36,则 parseInt() 将返回 NaN。 |
copyed from W3School
['1', '2', '3'].map(parseInt)等价于[parseInt('1',0), parseInt('2',1), parseInt('3',2)]
总之 radix在[2-9]区间内 Number(string.charAt(0)) 不能大于等于 radix
0x和0X开头的默认都是 16进制字符串转10进制 如果指定了radix 那么都是按常规字符串处理=>0
基数为1(1进制)的时候,返回的结果都是NaN,所以parseInt('2', 1)返回结果是NaN
基数为2(2进制)的时候,字符串的值要求是0和1,所以parseInt('3', 2)返回结果是NaN
根据上边大家所述的原理,事实上如果想要完成字符串转化为数字的工作,应该将进制限制下来:
> ['1','2','3'].map(n=>parseInt(n,10))
<- [1, 2, 3]
当然最简单就是干脆别传这个index了,免得像parseInt()这种可以接受多个参数的函数面对一大堆参数时不知所措
> ['1','2','3'].map(n=>parseInt(n))
<- [1, 2, 3]
其实这个可以用函数式思维来解决,具体可以看月影老师写的这篇博文
parseInt('11', "4") 这个为啥等于5呢,他4进制,11应该也不在其范围内么,怎么会得出的结果为5呢
parseInt('11', "4") 这个为啥等于5呢,他4进制,11应该也不在其范围内么,怎么会得出的结果为5呢
'11'表示的是4进制的数啊 5 是十进制 1=>1 2=>2 3=>3 10=>4 11=>5
没有包含大于三的数字 就可以 懂了吗
parseInt('11', "4") 这个为啥等于5呢,他4进制,11应该也不在其范围内么,怎么会得出的结果为5呢
第一步,“11”以非"0x" or "0X" or "0" 开头,“11”转为数字11,即parseInt(11, "4")。
第二步, 基数是4,表示4进制,11表示4进制的数,parseInt转换4进制数11为10进制,4^0 + 4^1 = 5。 总结:parseInt('11', "4") 输出为10进制5。
明白了,谢谢
我开始也这么理解:第二个参数需要的范围是2~36之间,如果小于 2 或者大于 36,则 parseInt() 将返回 NaN。但是parseInt(5,4),第二个参数在[2,36]之间,但是结果依旧返回NaN啊。
所以后俩返回NaN,我们是不是又两种角度可以理解呢?
你这是两个问题
第1 超出2-36这个范围的有一个特殊数字0是允许的。如果是0则看字符串是否以0x,0开头,若以0x开头解析成16进制,0开头以前有版本解析成8进制,现在的规范基本都解析成10进制,还有其他的一些约束,可以看一下官方文档
第2 parseInt('5',4)为什么会返回NaN,因为4进制中只有0,1,2,3这几个数字,跟2进制中只有0,1这两个数一样。5已经超出4进制的范围了(可以用4进制来表述10进制的5),所以返回NaN
根据上边大家所述的原理,事实上如果想要完成字符串转化为数字的工作,应该将进制限制下来:
> ['1','2','3'].map(n=>parseInt(n,10)) <- [1, 2, 3]
当然最简单就是干脆别传这个index了,免得像parseInt()这种可以接受多个参数的函数面对一大堆参数时不知所措
> ['1','2','3'].map(n=>parseInt(n)) <- [1, 2, 3]
一般对我来说,在平时coding时,都是箭头函数,这点能避免很多问题的,另外 parseInt在使用时,我一般都是会加上第二个参数为10
根据上边大家所述的原理,事实上如果想要完成字符串转化为数字的工作,应该将进制限制下来:
> ['1','2','3'].map(n=>parseInt(n,10)) <- [1, 2, 3]
当然最简单就是干脆别传这个index了,免得像parseInt()这种可以接受多个参数的函数面对一大堆参数时不知所措
> ['1','2','3'].map(n=>parseInt(n)) <- [1, 2, 3]
一般对我来说,在平时coding时,都是箭头函数,这点能避免很多问题的,另外 parseInt在使用时,我一般都是会加上第二个参数为10
这么多答案,而且那些答案也说得有理有据,分析得非常深入
但是,还是觉得你的最正确
@thinkfish 哈哈 实际应用肯定是最小减少问题,但原理了解透彻还是很有必要的嘛
@thinkfish 哈哈 实际应用肯定是最小减少问题,但原理了解透彻还是很有必要的嘛
在理,至少在遇到问题的时候能快速定位
在30-seconds-of-code看到一个这个题的变形,分享一下
let unary = fn => val => fn(val) let parse = unary(parseInt) console.log(['1.1', '2', '0.3'].map(parse))
这种方法绕过了parseInt的第二个参数,实际执行如下:
console.log(['1.1', '2', '0.3'].map( item => {
return parseInt(item)
}))
花里胡哨的。
@developement711
parseInt的第二个参数:radix参数为n 将会把第一个参数看作是一个数的n进制表示,而返回的值则是十进制
例如: parseInt('11', 4) // 将'11'看作4进制数,返回十进制数5 => 1*4^1 + 1*4^0 = 5
['1', '2', '2'].map(i => ~~i)
不过数字大一些就不行
['99999999', '29999999999', '2'].map(i => ~~i)
-> [99999999, -64771073, 2]
在30-seconds-of-code看到一个这个题的变形,分享一下
let unary = fn => val => fn(val) let parse = unary(parseInt) console.log(['1.1', '2', '0.3'].map(parse))
这一题没看懂啥意思....
主要这个 unary 函数 不是很懂
unary
Creates a function that accepts up to one argument, ignoring any additional arguments.
Call the provided function,
fn
, with just the first argument given.const unary = fn => val => fn(val);
其实这个函数名就已经说明该函数可以被用来干啥,unary 单词的意思是一元,元本身是数量(货币)单位,例如一元钱。如果不明白的话,看 30-seconds-of-code 给出的例子以及英文解释也能很快地知道函数的用途。
unary
函数在执行的过程中,会创建并且返回一个函数,该返回函数最多接受一个参数,然后忽略其余的任何参数。
在只给出第一个参数的情况下,调用函数 unary
所提供的函数 fn
题外话,在不指定第二个参数的情况下执行 parseInt
,可能会存在兼容性问题。当然你不传第二个参数 radix
或者显式地传 0、undefined
也是可以的,因为 parseInt
会把这些情况统一处理成第二个参数为 10,然后执行 parseInt(str, 10)
。也正是因为兼容性问题,eslint
会提示你显式指定 parseInt
第二个参数 radix
parseInt(string, radix) 中,若radix参数为n, 则会把第一个参数看作是一个数的n进制表示,而返回的值则是十进制的。我觉得很多搞糊涂的看看这句话就不糊涂了,比如我。
看了大家的讨论,晕了下,再综合自己的看法,现在大概懂了
梳理一下自己的理解
以例子来说明
- 第二位(radix)默认为10(十进制)
parseInt(10) // 10
parseInt(10, 10) // 10
- radix取2-36
parseInt(10, 1) // NaN
parseInt(10, 3) // 3
parseInt(10, 37) // NaN
- 如何计算最终输出?
parseInt(10, 3)
首先第一位(string)中, 每一位都小于3(1 < 3 && 0 < 3),并且 radix在2到36之间 ,所以这时候我们应该是有个正确的输出的 。
计算: 现在是三进制,则输出结果为:0 * (3^0) + 1 * (3^1) = 3 ==>输出 3
parseInt(101, 2) // 5
同理, 101每一位都小于3(1 < 2 && 0 < 2),并且 radix在2到36之间
计算: 现在是2进制,则输出结果为:1 * (2^0) + 0 * (2^1) + 1 * (2^2) = 5 ==>输出 5
parseInt(102, 2) // 2
在102中 ,第三位2 >= 2 (第二位,即radix = 2) ,并且 radix在2到36之间
这个时候忽略大于等于radix位及其之后的所有数值 。则现在 102 ==> 10
计算: 现在是2进制,则输出结果为:0 * (2^0) + 1 * (2^1) = 2 ==>输出 2
parseInt(1061, 3) // 3
在102中 ,第2位 6 >= 2 (第二位,即radix = 2) ,并且 radix在2到36之间
这个时候忽略大于等于radix位及其之后的所有数值 。则现在 1061 ==> 10
计算: 现在是2进制,则输出结果为:0 * (3^0) + 1 * (3^1) = 3 ==>输出 3
parseInt(3061, 3) // NaN
第一位大于等于radix时,NaN
语法
parseInt(string, radix)
参数 | 描述
string | 必需。要被解析的字符串。
radix | 可选。表示要解析的数字的基数。该值介于 2 ~ 36 之间。如果省略该参数或其值为 0,则数字将以 10 为基础来解析。如果它以 “0x” 或 “0X” 开头,将以 16 为基数。如果该参数小于 2 或者大于 36,则 parseInt() 将返回 NaN。
以上是官方解释
还有一种情况会返回NaN,只要第二位的数字小于等于第一位时
parseInt('3',2)
NaN
parseInt('3',3)
NaN
parseInt('3',4)
3
parseInt('2',4)
2
parseInt('4',4)
NaN
parseInt('4',5)
4
parseInt('41',5)
21
parseInt('2',2)
NaN
parseInt('1',2)
1
parseInt('1',0)
1
parseInt('2',0)
2
parseInt('37',36)
115
MDN上关于parseInt的介绍:
语法
parseInt(string, radix);
参数
string
要被解析的值。如果参数不是一个字符串,则将其转换为字符串(使用 ToString 抽象操作)。字符串开头的空白符将会被忽略。
radix
一个介于2和36之间的整数(数学系统的基础),表示上述字符串的基数。比如参数"10"表示使用我们通常使用的十进制数值系统。始终指定此参数可以消除阅读该代码时的困惑并且保证转换结果可预测。当未指定基数时,不同的实现会产生不同的结果,通常将值默认为10。
原题写法相当于:
['1','2','3'].map((item,index)=>{
return parseInt(item,index)
})
当index为0时,代表parseInt忽略了第二个参数,此时以十进制表示,返回1。 当index为1时 输入不合法,parseInt第二个参数需要介于 2-36之间,返回NAN。当item为3 index为2时,3不是有效的2进制数 返回NAN
👍
['1', '2', '3'].map(item => parseInt(item,10))
答案: [1, NaN, NaN]
map将数组中的每个元素都执行一遍参数中的函数,新值作为新数组的元素,并返回新的数组。
var new_array = arr.map(function callback(currentValue[, index[, array]]) {
// Return element for new_array
}[, thisArg])
currentValue: 当前元素值
index: 当前元素索引
parseInt函数接收两个参数,返回一个整数或者NaN
string: 字符串,传入值不是字符串,会转换
radix: 2-36整数,表示基数(进制)
radix为空或者0的时候:
若string为‘0x’、'0X'开头,radix=16;
其余radix=10
因为每个元素的函数调用情况:
parseInt(‘1’, 0); //1
parseInt(‘2’, 1);//NaN
parseInt(‘3’, 2);//二进制每位不超过1 3超过1
在30-seconds-of-code看到一个这个题的变形,分享一下
let unary = fn => val => fn(val) let parse = unary(parseInt) console.log(['1.1', '2', '0.3'].map(parse))
这种方法绕过了parseInt的第二个参数,实际执行如下:
console.log(['1.1', '2', '0.3'].map( item => {
return parseInt(item)
}))
花里胡哨的。
感觉高级点。。
参数radix表示字符串基数,范围在 2-36 之间的整数
在基数为 undefined,或者基数为 0 或者没有指定的情况下,JavaScript 作如下处理:
- 如果字符串 string 以"0x"或者"0X"开头, 则基数是16 (16进制).
- 如果字符串 string 以"0"开头, 基数是8(八进制)或者10(十进制),那么具体是哪个基数由实现环境决定。ECMAScript 5 规定使用10,但是并不是所有的浏览器都遵循这个规定。
- 如果字符串 string 以其它任何值开头,则基数是10 (十进制)。
因此,永远都要明确给出radix参数的值,否则有概率得不到预期结果。
一、what 正确答案
['1', '2', '3'].map(parseInt); // [1,NaN,NaN]
二、why
(一)理解map
1、map概念
map() 方法创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果。
"map"即"映射",也就是原数组被"映射"成对应新数组。
新建一个数组,需要有承载对象,也意味着原始数组在调用它后不会发生变化;
该数组中的每个元素都调用一个提供的函数后返回结果。
var array1 = [1, 4, 9, 16];
const map1 = array1.map(x => x * 2);
console.log(map1); //输 出: Array [2, 8, 18, 32]
2、用JavaScript实现map
if (!Array.prototype.map) {
Array.prototype.map = function(callback, thisArg) {
var T, A, k;
if (this == null) {
throw new TypeError(" this is null or not defined");
}
// 1. 将O赋值为调用map方法的数组.
var O = Object(this);
// 2.将len赋值为数组O的长度.
var len = O.length >>> 0;
// 3.如果callback不是函数,则抛出TypeError异常.
if (Object.prototype.toString.call(callback) != "[object Function]") {
throw new TypeError(callback + " is not a function");
}
// 4. 如果参数thisArg有值,则将T赋值为thisArg;否则T为undefined.
if (thisArg) {
T = thisArg;
}
// 5. 创建新数组A,长度为原数组O长度len
A = new Array(len);
// 6. 将k赋值为0
k = 0;
// 7. 当 k < len 时,执行循环.
while(k < len) {
var kValue, mappedValue;
//遍历O,k为原数组索引
if (k in O) {
//kValue为索引k对应的值.
kValue = O[ k ];
// 执行callback,this指向T,参数有三个.分别是kValue:值,k:索引,O:原数组.
mappedValue = callback.call(T, kValue, k, O);
// 返回值添加到新数组A中.
A[ k ] = mappedValue;
}
// k自增1
k++;
}
// 8. 返回新数组A
return A;
};
}
(二)理解parseInt
1、parseInt 概念
parseInt() 函数解析一个字符串参数,并返回一个指定基数的整数 (数学系统的基础)。
parseInt(string, radix);
- string 表示
要被解析的值。如果参数不是一个字符串,则将其转换为字符串(使用 ToString 抽象操作)。字符串开头的空白符将会被忽略。 - radix表示
一个介于2和36之间的整数(数学系统的基础),表示上述字符串的基数。比如参数"10"表示使用我们通常使用的十进制数值系统。始终指定此参数可以消除阅读该代码时的困惑并且保证转换结果可预测。当未指定基数时,不同的实现会产生不同的结果,通常将值默认为10。
2、 返回值
返回解析后的整数值。 如果被解析参数的第一个字符无法被转化成数值类型,则返回 NaN。
parseInt("Hello", 8); // 输出NaN, 因为根本就不是数值
parseInt("546", 2); // 输出NaN,因为除了“0、1”外,其它数字都不是有效二进制数字
参考文章
第一眼看到这个题目的时候,脑海跳出的答案是 [1, 2, 3],但是真正的答案是[1, NaN, NaN]。
- 首先让我们回顾一下,map函数的第一个参数callback:
var new_array = arr.map(function callback(currentValue[, index[, array]]) { // Return element for new_array }[, thisArg])
这个callback一共可以接收三个参数,其中第一个参数代表当前被处理的元素,而第二个参数代表该元素的索引。
- 而parseInt则是用来解析字符串的,使字符串成为指定基数的整数。
parseInt(string, radix)
接收两个参数,第一个表示被处理的值(字符串),第二个表示为解析时的基数。- 了解这两个函数后,我们可以模拟一下运行情况
- parseInt('1', 0) //radix为0时,且string参数不以“0x”和“0”开头时,按照10为基数处理。这个时候返回1
- parseInt('2', 1) //基数为1(1进制)表示的数中,最大值小于2,所以无法解析,返回NaN
- parseInt('3', 2) //基数为2(2进制)表示的数中,最大值小于3,所以无法解析,返回NaN
- map函数返回的是一个数组,所以最后结果为[1, NaN, NaN]
- 最后附上MDN上对于这两个函数的链接,具体参数大家可以到里面看
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/parseInt
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/map
浏览器运行如下,感觉第2点有点问题,这个时候应该 radix 不满足[2, 36]的整数,所以 NaN比较合理。
parseInt('1', 1)
NaN
parseInt('0', 1)
NaN
在30-seconds-of-code看到一个这个题的变形,分享一下
let unary = fn => val => fn(val)
let parse = unary(parseInt)
console.log(['1.1', '2', '0.3'].map(parse))这种方法绕过了parseInt的第二个参数,实际执行如下:
console.log(['1.1', '2', '0.3'].map( item => {
return parseInt(item)
}))
花里胡哨的。
这个出题人这样出题太不好了
let unary = fn => val => fn(val) 这句话等同于 let unary = fn, 后面搞那么多没用的干什么
根据上边大家所述的原理,事实上如果想要完成字符串转化为数字的工作,应该将进制限制下来:
['1','2','3'].map(n=>parseInt(n,10))
<- [1, 2, 3]当然最简单就是干脆别传这个index了,免得像parseInt()这种可以接受多个参数的函数面对一大堆参数时不知所措
['1','2','3'].map(n=>parseInt(n))
<- [1, 2, 3]
这样的解释跟本说不通。虽然结果一样
从原理上来讲map方法接受一个cb,并且传入cb 3个参数,至于cb用不用那是自己的事情
类似 function map (cb) { cb(a,b,c) }
题目中cb本身就是parseInt ,你的解法是自己强行添加了一个cb,等于是换掉cb
我开始也这么理解:第二个参数需要的范围是2~36之间,如果小于 2 或者大于 36,则 parseInt() 将返回 NaN。但是parseInt(5,4),第二个参数在[2,36]之间,但是结果依旧返回NaN啊。
所以后俩返回NaN,我们是不是又两种角度可以理解呢?
parseInt(string, radix) string为字符串,radix为介于2-36之间的数。使用者告诉这个函数string(比如11)是radix(比如2)进制的,函数将固定返回string以十进制时显示的数(3)。
涉及知识点
- map函数的默认传参
callback 函数会被自动传入三个参数:数组元素,元素索引,原数组本身
var new_array = arr.map(function callback(currentValue[, index[, array]]) {
// Return element for new_array
}[, thisArg])
- parseInt()函数的入参
parseInt(string, radix)
string为字符串,要被解析的值。如果参数不是一个字符串,则将其转换为字符串
radix为介于2-36之间的数
- 进制规范
parseInt('11',2) //3
2进制没有大于等于2的数
3进制没有大于等于3的数
parsrInt('3',2) //NaN
- 最后结果
//实际执行
['1', '2', '3'].map(parseInt)
parseInt('1', 0) //1
parseInt('2', 1) //NaN
parseInt('3', 2) //NaN
//结果 [1, NaN, NaN]
- 避免方法
- 指定parseInt()第二个参数
var _parseInt = n => parseInt(n,10)
['1', '2', '3'].map(_parseInt)
- 确定map传参
['1', '2', '3'].map(n=>parseInt(n))
- �其他注意点
parseInt('hello123') //NaN
Number('hell123') //NaN
//正则匹配数字再用数字转化方法
parseInt的第二个参数是多少,就会把第一个参数当成多少进制,然后返回十进制数,显然parseInt('3', 2)是一种错误的2进制数,所以解析不出来,返回NaN
`console.log(['10','2','10','10','10',"23","625"].map((item,index)=>{
return parseInt(item,index)
}))
// radix为0时,且string参数不以“0x”和“0”开头时,按照10为基数处理
// parseInt('10',0) -> 10*(10^0)=10
// parseInt('10',1) ->NaN,基数值介于 2 ~ 36 之间,1不在范围之内,不能解析。
// parseInt('10',2) -> 10转为2进制,1*(2^1)+0*(2^0)=2
// parseInt('10',3) ->1*(3^1)+0*(3^0)=3
// parseInt('10',4) ->1*(4^1)+0*(4^0)=4
// parseInt('23',5) ->2*(5^1)+3*(5^0)=13,多位数,每一位都小于基数的,按照进制算,
// parseInt('66',6) ->NaN, 多位数,每一位都大于等于基数的,NaN
// parseInt('255',6) ->107,2*(6^2)+5*(6^1)+5*(6^0)
// parseInt('265',6) ->2 ,有一位数大于等于基数,直接截取未超过基数的数字
// console.log(parseInt("4",8)) ->4, 4*(8^0) = 4
// 一位数,不能大于等于基数,不然就返回NaN`
一起学习交流,大家可以看下我的解读:
https://juejin.im/post/5d21ab6a5188255c23554096
以为自己真明白了,过去一段时间,再看此题,又模糊了,那,这次真正把它弄明白!
准备只是,进制:
2进制,基数只能为 0,1
3进制,基数为0,1,2
4进制,基数为0,1,2,3
5进制,基数为0,1,2,3,4
...
8进制,基数为0,1,2,3,4,5,6,7
10进制,基数为0,1,2,3,4,5,6,7,8,9
16进制,基数为0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f
发现一个规律,基数们都小于 < 进制数
如 2进制数 的基数 0 和1 都小于2对吧!
继续往下看:
parseInt(str, radix)
str:字符串
radix: 几进制呀
当 radix >0 && (radix>36 || radix < 2) 返回NAN
当 radix = 0 或没传即(radix=undefined)返回十进制
当正常情况下,
str左起第一个数一旦大于进制数radix,立马返回 NaN
str左起第一个数一旦小于进制数radix,就去做运算,直到遇到一个大于等于radix,就不加了哈!
如parseInt('4215213', 5) // 4*5 + 1 = 21
['1', '2', '3'].map(parseInt)
让其变形为
parseInt('1', 0); // 1
parseInt('2', 1); // NaN
parseInt('3', 2); // 由于 2的二进制数是 0 和 1 组成的,所以要返回 NaN
parseInt('1222', 2) //首位 1<2哎, 则 1
parseInt('213', 3); // 2* 3 + 1 = 7; 简单的我会算
['10', '10', '10', '10', '10'].map(parseInt)
parseInt('10', 0); // 10 无意义吧
parseInt('10', 1); // NaN ’10‘ 的首位 1>=1啦!直接NaN
parseInt('10', 2); // 1*2 + 0 = 2
parseInt('10', 3) // 1*3 + 0 = 3
parseInt('10', 4); // 1*4 + 0 = 4
进制换算不会自行查阅~
parseInt('11', 4) // 5的4进制是11。如果找不到,则为NaN
parseInt('3', 2) //基数为2(2进制)表示的数中,最大值小于3,所以无法解析,返回NaN
这句话解释的啥啊?
应该是'3'不是一个合法的二进制才对吧?
parseInt('1', 2) // 1
parseInt('10', 2) // 2
Map函数:map函数中的回调函数接收的两个参数,一个是数组元素,一个是数组元素下标。
parseInt函数:第一个参数为数值或者能转换成数值的其他类型的值,第二值为进制数,如果第一个参数不能被转换为数值则为NaN,如果第一个值大于等于第二个值,则为NaN。
parseInt('3', 2) //基数为2(2进制)表示的数中,最大值小于3,所以无法解析,返回NaN
这句话解释的啥啊?
应该是'3'不是一个合法的二进制才对吧?
parseInt('1', 2) // 1
parseInt('10', 2) // 2
parseInt('3', 2) //基数为2(2进制)表示的数中,最大值小于3,所以无法解析,返回NaN
就是说第一个参数永远不可能大于第二个参数。否则返回NaN
parseInt('11', "4") 这个为啥等于5呢,他4进制,11应该也不在其范围内么,怎么会得出的结果为5呢
14^1+14^0 = 4+1 = 5
parseInt 基数是一个介于2和36之间的整数 可能第二点这个说法不太准确
一、what 正确答案
['1', '2', '3'].map(parseInt); // [1,NaN,NaN]二、why
(一)理解map
1、map概念
map() 方法创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果。
"map"即"映射",也就是原数组被"映射"成对应新数组。
新建一个数组,需要有承载对象,也意味着原始数组在调用它后不会发生变化;
该数组中的每个元素都调用一个提供的函数后返回结果。var array1 = [1, 4, 9, 16]; const map1 = array1.map(x => x * 2); console.log(map1); //输 出: Array [2, 8, 18, 32]2、用JavaScript实现map
if (!Array.prototype.map) { Array.prototype.map = function(callback, thisArg) { var T, A, k; if (this == null) { throw new TypeError(" this is null or not defined"); } // 1. 将O赋值为调用map方法的数组. var O = Object(this); // 2.将len赋值为数组O的长度. var len = O.length >>> 0; // 3.如果callback不是函数,则抛出TypeError异常. if (Object.prototype.toString.call(callback) != "[object Function]") { throw new TypeError(callback + " is not a function"); } // 4. 如果参数thisArg有值,则将T赋值为thisArg;否则T为undefined. if (thisArg) { T = thisArg; } // 5. 创建新数组A,长度为原数组O长度len A = new Array(len); // 6. 将k赋值为0 k = 0; // 7. 当 k < len 时,执行循环. while(k < len) { var kValue, mappedValue; //遍历O,k为原数组索引 if (k in O) { //kValue为索引k对应的值. kValue = O[ k ]; // 执行callback,this指向T,参数有三个.分别是kValue:值,k:索引,O:原数组. mappedValue = callback.call(T, kValue, k, O); // 返回值添加到新数组A中. A[ k ] = mappedValue; } // k自增1 k++; } // 8. 返回新数组A return A; }; }(二)理解parseInt
1、parseInt 概念
parseInt() 函数解析一个字符串参数,并返回一个指定基数的整数 (数学系统的基础)。
parseInt(string, radix);
- string 表示
要被解析的值。如果参数不是一个字符串,则将其转换为字符串(使用 ToString 抽象操作)。字符串开头的空白符将会被忽略。- radix表示
一个介于2和36之间的整数(数学系统的基础),表示上述字符串的基数。比如参数"10"表示使用我们通常使用的十进制数值系统。始终指定此参数可以消除阅读该代码时的困惑并且保证转换结果可预测。当未指定基数时,不同的实现会产生不同的结果,通常将值默认为10。2、 返回值
返回解析后的整数值。 如果被解析参数的第一个字符无法被转化成数值类型,则返回 NaN。
parseInt("Hello", 8); // 输出NaN, 因为根本就不是数值 parseInt("546", 2); // 输出NaN,因为除了“0、1”外,其它数字都不是有效二进制数字参考文章
parseInt("Hello", 8); // 输出NaN, 因为根本就不是数值
parseInt("Hello", 8); // 输出NaN
这个输出NaN 的根本原因不是因为它不是数值,而是因为 后面的基数限制了。将字母按照 a=10, 这样依次排列之后,只要你的后面基数大于 字母对应的 数值,就能转换成数字。
比如:console.log( parseInt('hello', 36) ) // 29234652
console.log( parseInt(0xaa, 20) ) // 540
这个输出会先把 0xaa 按照十六进制转换为十进制数 170,然后再将 170 按照 20进制 转换 得到 540
console.log( parseInt('aaa', 20) ) // 4210
这个输出会 直接将 aaa 作为20进制解析,a=10, 10 * 20^0 + 10 * 20^1 + 10*20^2 = 4210
console.log( parseInt('ka', 20) ) // NaN
这个会 直接将 ka 作为20进制解析, 但因为要解析的字符串单个值必须小于 基数(20)而 k=20, 所以返回 NaN
所以 parseInt("Hello", 8); // 输出NaN,并不是因为hello不是数值(自己理解的)。
parseInt接受两个参数~1,0为十进制,2,1不存在,3,2不存在。
因此,1,nan,nan
我开始也这么理解:第二个参数需要的范围是2~36之间,如果小于 2 或者大于 36,则 parseInt() 将返回 NaN。但是parseInt(5,4),第二个参数在[2,36]之间,但是结果依旧返回NaN啊。
所以后俩返回NaN,我们是不是又两种角度可以理解呢?
parseInt第二参数表示的是第一个参数的进制表示,所以第一个参数不能越过这个进制的表示方法,比如二进制,那么单个字符最大不能超过2
最高赞的说法有点问题哈,第二点和第三点可能对进制理解的有误
2进制里面是没有2的,只有1、0,最小进制为2进制。
所以
parseInt('2', 1) //基数为1(1进制)表示的数中,最大值小于2,所以无法解析,返回NaN
parseInt('3', 2) //基数为2(2进制)表示的数中,最大值小于3,所以无法解析,返回NaN
关于第二点,第二个参数需要的范围是2~36之间,所以parseInt('0', 1),也会返回NaN。
第三点,parseInt('3', 2)最大值是小于2的。parseInt('2', 2),返回的依旧是NaN。
说实话,我还是没懂,为啥 ['10','10','10','10','10'].map(parseInt); => // [10, NaN, 2, 3, 4]
为啥parseInt("10",3) =>//3 ???
说实话,我还是没懂,为啥 ['10','10','10','10','10'].map(parseInt); => // [10, NaN, 2, 3, 4]
为啥parseInt("10",3) =>//3 ???
二进制,这里 3^1 +3^0 = 3
我开始也这么理解:第二个参数需要的范围是2~36之间,如果小于 2 或者大于 36,则 parseInt() 将返回 NaN。但是parseInt(5,4),第二个参数在[2,36]之间,但是结果依旧返回NaN啊。
所以后俩返回NaN,我们是不是又两种角度可以理解呢?
parseInt(3, 4) 就不会报错,4代表四进制, 四进制的话则需要parseInt的数就不会是大于数字3的数,因为逢4进1掉了, 大于3的数不合法.
在30-seconds-of-code看到一个这个题的变形,分享一下
let unary = fn => val => fn(val) let parse = unary(parseInt) console.log(['1.1', '2', '0.3'].map(parse))
能否给解释下
我开始也这么理解:第二个参数需要的范围是2~36之间,如果小于 2 或者大于 36,则 parseInt() 将返回 NaN。但是parseInt(5,4),第二个参数在[2,36]之间,但是结果依旧返回NaN啊。
所以后俩返回NaN,我们是不是又两种角度可以理解呢?
parseInt('5', 4)结果为NaN, 是因为在4进制中不存在5,因为满4就进1了,4进制中的5应该是11
以为自己真明白了,过去一段时间,再看此题,又模糊了,那,这次真正把它弄明白!
准备只是,进制:
2进制,基数只能为 0,1
3进制,基数为0,1,2
4进制,基数为0,1,2,3
5进制,基数为0,1,2,3,4
...
8进制,基数为0,1,2,3,4,5,6,7
10进制,基数为0,1,2,3,4,5,6,7,8,9
16进制,基数为0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f
发现一个规律,基数们都小于 < 进制数
如 2进制数 的基数 0 和1 都小于2对吧!继续往下看:
parseInt(str, radix)
str:字符串
radix: 几进制呀
当 radix >0 && (radix>36 || radix < 2) 返回NAN
当 radix = 0 或没传即(radix=undefined)返回十进制当正常情况下, str左起第一个数一旦大于进制数radix,立马返回 NaN str左起第一个数一旦小于进制数radix,就去做运算,直到遇到一个大于等于radix,就不加了哈! 如parseInt('4215213', 5) // 4*5 + 1 = 21
['1', '2', '3'].map(parseInt) 让其变形为 parseInt('1', 0); // 1 parseInt('2', 1); // NaN parseInt('3', 2); // 由于 2的二进制数是 0 和 1 组成的,所以要返回 NaN parseInt('1222', 2) //首位 1<2哎, 则 1 parseInt('213', 3); // 2* 3 + 1 = 7; 简单的我会算 ['10', '10', '10', '10', '10'].map(parseInt) parseInt('10', 0); // 10 无意义吧 parseInt('10', 1); // NaN ’10‘ 的首位 1>=1啦!直接NaN parseInt('10', 2); // 1*2 + 0 = 2 parseInt('10', 3) // 1*3 + 0 = 3 parseInt('10', 4); // 1*4 + 0 = 4进制换算不会自行查阅~
parseInt('4215213', 5) // 4 * 5^2+2 * 5^1+1 * 5^0 = 111 应该是这样的吧
如果你仔细点,同时也熟悉 parseInt 和 map 的语法,这道题说难也不难,不过要让面试官满意还是得花多点功夫。
或许许多人认为是 [1, 2, 3],但是真正的答案是[1, NaN, NaN]。
本人也把这个详细的说明归纳在本人的 github 上面,https://github.com/xianshannan/interview/issues/25
map 的语法
有点 JavaScript 基础的基本都知道 map 的基本用法。
const newArray = arr.map(function callback(currentValue[, index[, array]]) {
// Return element for new_array
}[, thisArg])
callback
可以接收三个参数,其中第一个参数代表当前被处理的元素,而第二个参数代表该元素的索引,第三个参数代表数组本身。
parseInt 语法
parseInt(string, radix);
parseInt(string, radix) 将一个字符串 string 转换为 radix 进制的整数, radix 为介于 2-36 之间的数。
radix
参数为 n 将会把第一个参数看作是一个数的 n 进制表示,而返回的值则是十进制。
如果被解析参数的第一个字符无法被转化成数值类型,则返回 NaN,第一个字符不为数字或者大于等于进制数,就会返回 NAN。
当 radix 为 0 、false、null、undefined,如果 string 不包含 0x,一般默认为十进制。
进制转换规则
假设 n 为进制,1ND 为第一位数,2ND 为第二数(以此类推),result 为结果,二位数的转换规则如下:
result => 1ND * n ^ 1 + 2ND * n ^ 0 = 3
js 语法如下:
1ND * Math.pow(n,1) + 2ND * Math.pow(n,0)
假设 n 为进制,result 为结果,三位数的转换规则如下:
result => 1ND * n ^ 2 + 2ND * n ^ 1 + 3ND * n ^ 0 = 3
js 语法如下:
1ND * Math.pow(n,2) + 2ND * Math.pow(n,1) + 3ND * Math.pow(n,0)
假设 n 为进制,result 为结果,四位数的转换规则如下:
result => 1ND * n ^ 3 + 2ND * n ^ 2 + 3ND * n ^ 1 + 4ND * n ^ 0= 3
js 语法如下:
1ND * Math.pow(n,3) + 2ND * Math.pow(n,2) + 3ND * Math.pow(n,1) + 4ND * Math.pow(n,0)
一些例子运行情况
-
当 radix 为 0 、false、null、undefined,如果 string 不包含 0x,一般默认为十进制。
parseInt('1', 0) parseInt('1') parseInt('1', false) parseInt('1', null)
上面的返回结果都为 1.
-
radix 为介于 2-36之间,基数为 1 无效,所以无法解析,返回 NaN
parseInt('0', 1) parseInt('2', 1)
上面的返回结果都为 NAN.
-
第一个字符不为数字或者大于等于进制数,就会返回 NAN。
parseInt('dd', 2) parseInt(null, 2) parseInt('2', 2) parseInt('3', 2) parseInt('4', 4) parseInt('5', 4)
上面的返回结果都为 NAN.
参考资料
如果你仔细点,同时也熟悉 parseInt 和 map 的语法,这道题说难也不难,不过要让面试官满意还是得花多点功夫。
或许许多人认为是 [1, 2, 3],但是真正的答案是[1, NaN, NaN]。
本人也把这个详细的说明归纳在本人的 github 上面,https://github.com/xianshannan/interview/issues/25。
map 的语法
有点 JavaScript 基础的基本都知道 map 的基本用法。
const newArray = arr.map(function callback(currentValue[, index[, array]]) { // Return element for new_array }[, thisArg])
callback
可以接收三个参数,其中第一个参数代表当前被处理的元素,而第二个参数代表该元素的索引,第三个参数代表数组本身。parseInt 语法
parseInt(string, radix);parseInt(string, radix) 将一个字符串 string 转换为 radix 进制的整数, radix 为介于 2-36 之间的数。
radix
参数为 n 将会把第一个参数看作是一个数的 n 进制表示,而返回的值则是十进制。如果被解析参数的第一个字符无法被转化成数值类型,则返回 NaN,第一个字符不为数字或者大于等于进制数,就会返回 NAN。
当 radix 为 0 、false、null、undefined,如果 string 不包含 0x,一般默认为十进制。
进制转换规则
假设 n 为进制,1ND 为第一位数,2ND 为第二数(以此类推),result 为结果,二位数的转换规则如下:
result => 1ND * n ^ 1 + 2ND * n ^ 0 = 3js 语法如下:
1ND * Math.pow(n,1) + 2ND * Math.pow(n,0)假设 n 为进制,result 为结果,三位数的转换规则如下:
result => 1ND * n ^ 2 + 2ND * n ^ 1 + 3ND * n ^ 0 = 3js 语法如下:
1ND * Math.pow(n,2) + 2ND * Math.pow(n,1) + 3ND * Math.pow(n,0)假设 n 为进制,result 为结果,四位数的转换规则如下:
result => 1ND * n ^ 3 + 2ND * n ^ 2 + 3ND * n ^ 1 + 4ND * n ^ 0= 3js 语法如下:
1ND * Math.pow(n,3) + 2ND * Math.pow(n,2) + 3ND * Math.pow(n,1) + 4ND * Math.pow(n,0)一些例子运行情况
当 radix 为 0 、false、null、undefined,如果 string 不包含 0x,一般默认为十进制。
parseInt('1', 0) parseInt('1') parseInt('1', false) parseInt('1', null)上面的返回结果都为 1.
radix 为介于 2-36之间,的数基数为 1 无效,所以无法解析,返回 NaN
parseInt('0', 1) parseInt('2', 1)上面的返回结果都为 NAN.
第一个字符不为数字或者大于等于进制数,就会返回 NAN。
parseInt('dd', 2) parseInt(null, 2) parseInt('2', 2) parseInt('3', 2) parseInt('4', 4) parseInt('5', 4)上面的返回结果都为 NAN.
参考资料
map 回调函数放内置函数原理是什么?
eg:
let newArr=['1','2','3'].map((item,index)=>parseInt(item,index));
let newArr=['1','2','3'].map(parseInt);
参数是怎样传递对应
如果面试中遇到这个问题,我应该会这样回答,不知道算不算答对
['1', '2', '3'].map(parseInt)
等价于
['1', '2', '3'].map((item,index)=>{
console.log(parseInt(item,index));
});
考点是不是在parseInt的转换基数,我在控制台输出的结果是一致的;
我开始也这么理解:第二个参数需要的范围是2~36之间,如果小于 2 或者大于 36,则 parseInt() 将返回 NaN。但是parseInt(5,4),第二个参数在[2,36]之间,但是结果依旧返回NaN啊。
所以后俩返回NaN,我们是不是又两种角度可以理解呢?
parseInt(5,4) 4进制中没有5这个数值,无法解析,当然返回NaN
我有一个问题
parseInt('14', 2) // 1
返回的结果为什么是 1?
['1','2','3'].map(parseInt)默认是
['1','2','3'].map((item,index)=>parseInt(item,index)); // [1, NaN, NaN]
修改默认不传index就可以了
['1','2','3'].map((item,index)=>parseInt(item));// [1, 2, 3]
(为什么parseInt默认会这样,我也想知道)
在30-seconds-of-code看到一个这个题的变形,分享一下
let unary = fn => val => fn(val) let parse = unary(parseInt) console.log(['1.1', '2', '0.3'].map(parse))
这个的答案是什么呢?
首先看看 parseInt 方法在 MDN 的文档
parseInt(string, radix);
string
要被解析的值。如果参数不是一个字符串,则将其转换为字符串(使用 ToString 抽象操作)。字符串开头的空白符将会被忽略。radix
一个介于2和36之间的整数(数学系统的基础),表示上述字符串的基数。比如参数 10 表示使用十进制数值系统。始终指定此参数可以消除阅读该代码时的困惑并且保证转换结果可预测。当未指定基数时,不同的实现会产生不同的结果,通常认为其值默认为10,但是如果你的代码运行在过时的浏览器中,那么请在使用时总是显式地指定 radix。返回值
返回解析后的整数值。 如果被解析参数的第一个字符无法被转化成数值类型,则返回 NaN
接下来分析 map 中的每一次迭代调用 parseInt 的参数:
parseInt('1', 0, ['1', '2', '3'])
输出1
parseInt('2', 1, ['1', '2', '3'])
输出NaN
parseInt('3', 2, ['1', '2', '3'])
输出NaN
所以结果为:[1, NaN, NaN]
首先看看 parseInt 方法在 MDN 的文档
parseInt(string, radix);
string
要被解析的值。如果参数不是一个字符串,则将其转换为字符串(使用 ToString 抽象操作)。字符串开头的空白符将会被忽略。
radix
一个介于2和36之间的整数(数学系统的基础),表示上述字符串的基数。比如参数 10 表示使用十进制数值系统。始终指定此参数可以消除阅读该代码时的困惑并且保证转换结果可预测。当未指定基数时,不同的实现会产生不同的结果,通常认为其值默认为10,但是如果你的代码运行在过时的浏览器中,那么请在使用时总是显式地指定 radix。
返回值
返回解析后的整数值。 如果被解析参数的第一个字符无法被转化成数值类型,则返回 NaN接下来分析 map 中的每一次迭代调用 parseInt 的参数:
1. `parseInt('1', 0, ['1', '2', '3'])` 输出 `1` 2. `parseInt('2', 1, ['1', '2', '3'])` 输出 `NaN` 3. `parseInt('3', 2, ['1', '2', '3'])` 输出 `NaN`
所以结果为:
[1, NaN, NaN]
谢谢回答,但是我想请问的是关于那个变形题的答案
let unary = fn => val => fn(val)
let parse = unary(parseInt)
console.log(['1.1', '2', '0.3'].map(parse))
这个的答案能否解释一下呢?
在30-seconds-of-code看到一个这个题的变形,分享一下
let unary = fn => val => fn(val) let parse = unary(parseInt) console.log(['1.1', '2', '0.3'].map(parse))
这个的答案是什么呢?
我是这样理解的:
unary
函数接收一个回调函数 fn
,返回一个闭包。
也就是说 parse
函数等同于 let parse = val => parseInt(val)
传入 parse
函数的参数依次是(箭头函数没有 arguments
所以超过形参的实参会被忽略):
parse('1.1')
返回1
parse('2')
返回2
parse('0.3')
返回0
输出 [1, 2, 0]
在30-seconds-of-code看到一个这个题的变形,分享一下
let unary = fn => val => fn(val) let parse = unary(parseInt) console.log(['1.1', '2', '0.3'].map(parse))
这个的答案是什么呢?
我是这样理解的:
unary
函数接收一个回调函数fn
,返回一个闭包。也就是说
parse
函数等同于let parse = val => parseInt(val)
传入
parse
函数的参数依次是(箭头函数没有arguments
所以超过形参的实参会被忽略):1. `parse('1.1')` 返回 `1` 2. `parse('2')` 返回 `2` 3. `parse('0.3')` 返回 `0`
输出
[1, 2, 0]
谢谢回答~
做完每一题(学习技术一定要以一手资料为主):
题目2答案:分别分析了specification里面是如何描述 parseInt 和 Array.prototype.map 的。
这题的考察点有三个:
- Array.map方法callback函数的参数问题
- JS函数的实参、形参。
- parseInt方法的使用,其第二个参数的意思及规则
Array.map方法的callback函数接收三个参数,(value, index, array)。
而parseInt方法接收两个参数。这里就涉及到函数参数个数问题了,在JS中,不看形参的,看实参,就是你传多少个参数给我无所谓,我函数内部只用我需要的,其内部使用arguments进行引用,具体机制可以查阅相关资料文章。
比如这里的parseInt方法,虽然map的callback给它传了三个参数,但是它只会用到前两个参数,也就是map函数callback的value和index。
所以题目就转化成了如下形式:
['1', '2', '3'].map(parseInt) = [parseInt('1', 0), parseInt('2', 1), parseInt('3', 2)]
而接下来,你就要知道parseInt方法的参数意义了:
parseInt(string, radix)
参数 | 描述 |
---|---|
string | 必需。要被解析的字符串。 |
radix | 可选。表示要解析的数字的基数。该值介于 2 ~ 36 之间。如果省略该参数或其值为 0,则数字将以 10 为基础来解析。如果它以 “0x” 或 “0X” 开头,将以 16 为基数。如果该参数小于 2 或者大于 36,则 parseInt() 将返回 NaN。 |
这是一些例子
parseInt("10"); //返回 10
parseInt("19",10); //返回 19 (10+9)
parseInt("11",2); //返回 3 (2+1)
parseInt("17",8); //返回 15 (8+7)
parseInt("1f",16); //返回 31 (16+15)
parseInt("010"); //未定:返回 10 或 8
从上面的解释可以知道:
parseInt('1', 0) = 1。
第二个参数为0,则默认基数是十,也就是'1',是十进制的数字字符串,转为数字自然就是1了。
parseInt('2', 1) = NaN。
第二个参数为1,小于2,所以值为NaN。
parseInt('3', 2) = NaN。
第二个参数为2,则说明'3'是二进制的数字字符串。然后3是个不合法的二进制(二进制有0和1组成),无法转换,所以值为NaN
所以最终的结果是:[1, NaN, NaN]
看了这个题目后专门去研究了parseInt,parseInt的参数
parseInt(String,radix)里的radix根本就没有这么简单,radix根本就不是单纯的进制,详情看我简书的文章
parseInt详解-你以为radix指的进制吗?
说实话,我还是没懂,为啥 ['10','10','10','10','10'].map(parseInt); => // [10, NaN, 2, 3, 4]
为啥parseInt("10",3) =>//3 ???二进制,这里
3^1 +3^0 = 3
大哥。。。parseInt("10",3)这里的3指的是三进制。而且3^0 = 1啊。。。你的公式3^1 +3^0 那是等于4的啊。。。
说实话,我还是没懂,为啥 ['10','10','10','10','10'].map(parseInt); => // [10, NaN, 2, 3, 4]
为啥parseInt("10",3) =>//3 ???二进制,这里
3^1 +3^0 = 3
大哥。。。parseInt("10",3)这里的3指的是三进制。而且3^0 = 1啊。。。你的公式3^1 +3^0 那是等于4的啊。。。
3^1 +3^0 = 3是不准确的,应该说是1 * 3^1 + 0 * 3^0 = 3,前面还要乘系数的,你想一下二进制的10为什么是2就明白了
看了这个题目后专门去研究了parseInt,parseInt的参数
parseInt(String,radix)里的radix根本就没有这么简单,radix根本就不是单纯的进制,详情看我简书的文章
parseInt详解-你以为radix指的进制吗?
parseInt('45', 5) //4 这个应该算是parseInt的内部处理,跟radix是不是进制数没有关系。
MDN文档上是这样写的:
如果 parseInt 遇到的字符不是指定 radix 参数中的数字,它将忽略该字符以及所有后续字符,并返回到该点为止已解析的整数值。 parseInt 将数字截断为整数值。 允许前导和尾随空格。
这题的考察点有三个:
- Array.map方法callback函数的参数问题
- JS函数的实参、形参。
- parseInt方法的使用,其第二个参数的意思及规则
Array.map方法的callback函数接收三个参数,(value, index, array)。
而parseInt方法接收两个参数。这里就涉及到函数参数个数问题了,在JS中,不看形参的,看实参,就是你传多少个参数给我无所谓,我函数内部只用我需要的,其内部使用arguments进行引用,具体机制可以查阅相关资料文章。
比如这里的parseInt方法,虽然map的callback给它传了三个参数,但是它只会用到前两个参数,也就是map函数callback的value和index。所以题目就转化成了如下形式:
['1', '2', '3'].map(parseInt) = [parseInt('1', 0), parseInt('2', 1), parseInt('3', 2)]
而接下来,你就要知道parseInt方法的参数意义了:
parseInt(string, radix)
参数 描述
string 必需。要被解析的字符串。
radix 可选。表示要解析的数字的基数。该值介于 2 ~ 36 之间。如果省略该参数或其值为 0,则数字将以 10 为基础来解析。如果它以 “0x” 或 “0X” 开头,将以 16 为基数。如果该参数小于 2 或者大于 36,则 parseInt() 将返回 NaN。
这是一些例子parseInt("10"); //返回 10 parseInt("19",10); //返回 19 (10+9) parseInt("11",2); //返回 3 (2+1) parseInt("17",8); //返回 15 (8+7) parseInt("1f",16); //返回 31 (16+15) parseInt("010"); //未定:返回 10 或 8
从上面的解释可以知道:
parseInt('1', 0) = 1。
第二个参数为0,则默认基数是十,也就是'1',是十进制的数字字符串,转为数字自然就是1了。
parseInt('2', 1) = NaN。
第二个参数为1,小于2,所以值为NaN。
parseInt('3', 2) = NaN。
第二个参数为2,则说明'3'是二进制的数字字符串。然后3是个不合法的二进制(二进制有0和1组成),无法转换,所以值为NaN
所以最终的结果是:[1, NaN, NaN]
parseInt('14', 2)
parseInt('14', 2) parseInt从参数的第一个字符开始解析,遇到无法解析的则忽略,'14'中的1在二进制中可以解析,而4则无法解析,因)此parseInt('14',2) 相当于parseInt('1', 2),计算出结果是1
map接收一个函数,函数第一个参数为当前遍历的值,第二个参数为index,然后parseInt函数,第一个参数为要解析的值,第二个参数为进制,根据这个进制返回对应的十进制整数。所以题目的返回值可以简化为
parseInt('1',0); //1 radix为0时,且string参数不以“0x”和“0”开头时,按照10为基数处理。这个时候返回1
parseInt('2',1); //NAN 第二个参数为2-36的整数,所以返回NaN
parseInt('3',2);// NAN 2进制,只有1和0
💛 ['1', '2', '3'].map(parseInt) what & why ? [1,NaN,NaN]
map里面的callBack函数(item,index,arr)=>{ return ...},所以 ['1', '2', '3'].map(parseInt)相当于执行:
parseInt('1',0);parseInt('2',1);parseInt('3',2);
parseInt(string, radix):将一个字符串 string 转换为 radix 进制的整数, radix 为介于2-36之间的数。
参数
string
要被解析的值。如果参数不是一个字符串,则将其转换为字符串(使用 ToString 抽象操作)。字符串开头的空白符将会被忽略。如果 radix 是 undefined、0或未指定的,JavaScript会假定以下情况:
- 如果输入的 string以 "0x"或 "0x"(一个0,后面是小写或大写的X)开头,那么 radix被假定为16,字符串的其余部分被解析为十六进制数。
- 如果输入的 string以 "0"(0)开头,radix被假定为 10 (十进制),但不是所有的浏览器都支持。因此,在使用 parseInt时,一定要指定一个 radix。
- 如果输入的 string 以任何其他值开头, radix 是 10 (十进制)。
radix 可选
从 2 到 36,代表该进位系统的数字。例如说指定 10 就等于指定十进位。请注意,通常预设值不是 10 进位!
返回值
从给定的字符串中解析出的一个整数。
或者 NaN,当
- radix 小于 2 或大于 36 ,或
- 第一个非空格字符不能转换为数字。
所以:
parseInt('1',0); 十进制,返回1;
parseInt('2',1); radix不属于2-36期间,返回NaN;
parseInt('3',2); 二进制,二进制只有0和1,返回NaN;
得 [1,NaN,NaN]
我开始也这么理解:第二个参数需要的范围是2~36之间,如果小于 2 或者大于 36,则 parseInt() 将返回 NaN。但是parseInt(5,4),第二个参数在[2,36]之间,但是结果依旧返回NaN啊。
所以后俩返回NaN,我们是不是又两种角度可以理解呢?
5不是有效的4进制的有效数字
我不是很明白,parseInt
的第二个参数是可选的,为什么在map
中使用就会将 item
和 index
都传给parseInt
做参数呢。
我开始也这么理解:第二个参数需要的范围是2~36之间,如果小于 2 或者大于 36,则 parseInt() 将返回 NaN。但是parseInt(5,4),第二个参数在[2,36]之间,但是结果依旧返回NaN啊。
所以后俩返回NaN,我们是不是又两种角度可以理解呢?
你这种情况基地为4,前面为5,肯定是NAN啊。parseInt(10,4) = 4 parseInt(11,4) = 5 。(满4进1)
觉得parseInt对于进制解析,比较好理解的类似parseInt('20',4) 结果是8,但是对于parseInt('21',4),结果是9,也比较好理解,但是!!!!对于parseInt('25',4),结果是2,这个会比较容易错乱,其实这里是因为5不是4进制以内的数字,所以这里等价于parseInt('2',4),所以结果是2,楼上说的满4进1说法,个人觉得并不准确
以为自己真明白了,过去一段时间,再看此题,又模糊了,那,这次真正把它弄明白!
准备只是,进制:
2进制,基数只能为 0,1
3进制,基数为0,1,2
4进制,基数为0,1,2,3
5进制,基数为0,1,2,3,4
...
8进制,基数为0,1,2,3,4,5,6,7
10进制,基数为0,1,2,3,4,5,6,7,8,9
16进制,基数为0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f
发现一个规律,基数们都小于 < 进制数
如 2进制数 的基数 0 和1 都小于2对吧!
继续往下看:
parseInt(str, radix)
str:字符串
radix: 几进制呀
当 radix >0 && (radix>36 || radix < 2) 返回NAN
当 radix = 0 或没传即(radix=undefined)返回十进制当正常情况下, str左起第一个数一旦大于进制数radix,立马返回 NaN str左起第一个数一旦小于进制数radix,就去做运算,直到遇到一个大于等于radix,就不加了哈! 如parseInt('4215213', 5) // 4*5 + 1 = 21
['1', '2', '3'].map(parseInt) 让其变形为 parseInt('1', 0); // 1 parseInt('2', 1); // NaN parseInt('3', 2); // 由于 2的二进制数是 0 和 1 组成的,所以要返回 NaN parseInt('1222', 2) //首位 1<2哎, 则 1 parseInt('213', 3); // 2* 3 + 1 = 7; 简单的我会算 ['10', '10', '10', '10', '10'].map(parseInt) parseInt('10', 0); // 10 无意义吧 parseInt('10', 1); // NaN ’10‘ 的首位 1>=1啦!直接NaN parseInt('10', 2); // 1*2 + 0 = 2 parseInt('10', 3) // 1*3 + 0 = 3 parseInt('10', 4); // 1*4 + 0 = 4进制换算不会自行查阅~
parseInt('4215213', 5) // 4 * 5^2+2 * 5^1+1 * 5^0 = 111 应该是这样的吧
好棒
很容易忽略 map 的第二个参数要传到 parseInt 的进制参数里,造成错误,这题有点意思!
这题的考察点有三个:
- Array.map方法callback函数的参数问题
- JS函数的实参、形参。
- parseInt方法的使用,其第二个参数的意思及规则
Array.map方法的callback函数接收三个参数,(value, index, array)。
而parseInt方法接收两个参数。这里就涉及到函数参数个数问题了,在JS中,不看形参的,看实参,就是你传多少个参数给我无所谓,我函数内部只用我需要的,其内部使用arguments进行引用,具体机制可以查阅相关资料文章。
比如这里的parseInt方法,虽然map的callback给它传了三个参数,但是它只会用到前两个参数,也就是map函数callback的value和index。所以题目就转化成了如下形式:
['1', '2', '3'].map(parseInt) = [parseInt('1', 0), parseInt('2', 1), parseInt('3', 2)]
而接下来,你就要知道parseInt方法的参数意义了:
parseInt(string, radix)
参数 描述
细绳 必需。要被解析的字符串。
基数 可选。表示要解析的数字的基数。该值介于 2 ~ 36 之间。如果省略该参数或其值为 0,则数字将以 10 为基础来解析。如果它以 “0x” 或 “0X” 开头,将以 16 为基数。如果该参数小于 2 或者大于 36,则 parseInt() 将返回 NaN。
这是一些例子parseInt("10"); //返回 10 parseInt("19",10); //返回 19 (10+9) parseInt("11",2); //返回 3 (2+1) parseInt("17",8); //返回 15 (8+7) parseInt("1f",16); //返回 31 (16+15) parseInt("010"); //未定:返回 10 或 8
从上面的解释可以知道:
parseInt('1',0)= 1。
第二个参数为0,则默认基数是十,也就是'1',是十进制的数字字符串,转为数字自然就是1了。
parseInt('2',1)= NaN。
第二个参数为1,小于2,所以值为NaN。
parseInt('3',2)= NaN。
第二个参数为2,则说明'3'是二进制的数字字符串。然后3是个不合法的二进制(二进制有0和1组成),无法转换,所以值为NaN
所以最终的结果是:[1, NaN, NaN]
map 返回三个参数,parseInt 就自动接收前两个参数的原因就是因为实参的原因吗?有相关的文章可以参考吗?
@xingorg1 不是这样的,
我开始也这么理解:第二个参数需要的范围是2~36之间,如果小于 2 或者大于 36,则 parseInt() 将返回 NaN。但是parseInt(5,4),第二个参数在[2,36]之间,但是结果依旧返回NaN啊。
所以后俩返回NaN,我们是不是又两种角度可以理解呢?
不是这样的,parseInt(5,4),会变成parseInt("5",4),但是如果4进制的话,字符串每个位置上的最大值肯定是小于等于4的
根据上边大家所述的原理,事实上如果想要完成字符串转化为数字的工作,应该将进制限制下来:
> ['1','2','3'].map(n=>parseInt(n,10)) <- [1, 2, 3]
当然最简单就是干脆别传这个index了,免得像parseInt()这种可以接受多个参数的函数面对一大堆参数时不知所措
> ['1','2','3'].map(n=>parseInt(n)) <- [1, 2, 3]
我觉得还是传使用是最好的