前言
在实际开发中,我们经常遇到将其他类型的值转换为
Number
类型的情况。一般可以通过Number()
函数、parseInt()
函数以及parseFloat()
函数进行转换,但是它们三者使用起来还是有一定区别和注意事项的。这篇文章我们就来聊聊这三个函数。
1.Number()函数
Number()函数可以用于将任何类型转换为Number类型,它在转换时遵循下列规则。
- 如果是数字,则按照对应的进制数据格式,统一转换为十进制并返回。
Number(10); // 10 Number(010); // 8 Number(0x10); // 16 复制代码
- 如果是Boolean类型的值,true将返回为“1”,false将返回“0”
Number(true); // 1 Number(false); // 0 复制代码
- 如果值为undefined,则返回"NaN"。
Number(undefined); // NaN 复制代码
- 如果值为null,则返回“0”
Number(null); // 0 复制代码
- 如果值为字符串类型,则遵循下列规则。
- 如果该字符串只包含数字,则会直接转换成十进制数,如果前面有0,则会直接忽略这个0。
Number('21'); // 21 Number('021'); // 21 复制代码
- 如果字符串是有效的浮点数形式,则会直接转换成对应的浮点数,前置的0会被清空,只保留一个。
Number('0.12'); // 0.12 Number('0.012'); // 0.12 复制代码
- 如果字符串是有效的十六进制形式,则会转换为对应的十进制数值。
Number('0x12'); // 18 Number('0x21'); // 33 复制代码
- 如果字符串是有效的八进制形式,则不会按照八进制转换,而是直接按照十进制转换并输出,因为前置的0会被直接忽略。
Number('010'); // 10 Number('0020'); // 20 复制代码
- 如果字符串为空或为连续的空格,则会转换为0
Number(''); // 0 Number(' '); // 0 复制代码
- 如果字符串不是上述5种情况之一,则返回“NaN”
Number('123a'); // NaN Number('a1.1'); // NaN 复制代码
- 如果值为对象类型,则会调用对象的
alueOf()
函数获取返回值,并将返回值按照上述步骤重新判断能否转换为Number
类型,如果都不满足,则会调用对象的toString()
函数获取返回值,并将返回的值重新按照上述步骤重新判断,如果还不能转换成Number
类型则返回"NaN"
。
let obj = { age: 21, valueOf: function() { return this.age; }, toString: function() { return 'good'; } }; Number(obj); // 21 复制代码
2. parseInt()函数
parseInt()
函数用于解析一个字符串,并返回指定的基数对应的整数值
。 语法格式如下:
parseInt(string, radix); 复制代码
radix表示的是进制转换的基数,数据范围是2~36
在使用parseInt()函数将字符串转换成整数时,需要注意以下5点:
- 非字符串类型转换为字符串类型
如果传入的参数是非字符串类型的情况,则需要将其优先抓换成字符串类型,即使传入的是
整型数据
。
parseInt('0x12', 16); // 18 parseInt(0x12, 16); // 24(0x12要先转换为'18') 复制代码
- 数据截取的前置匹配原则
parseInt()函数在做转换时,会从字符串的第一个字符开始匹配,如果处于基数指定的范围,则保留并继续往后匹配满足条件的字符,直到某个字符不满足基数指定的数据范围,则从该字符开始,舍弃后面的全部字符。
parseInt('fg123', 16); // 15(舍弃掉g123) 复制代码
如果遇到的字符串是以“0x”开头的,那么按照十六进制处理时,会计算后面满足条件的字符串;如果按照十进制处理,则会直接返回“0”。
parseInt('0x12', 16); // 18 = 16 + 2 parseInt('0x12', 10); // 0 复制代码
如果传入的字符串中涉及算术运算,则不执行;如果传入的参数是算术表达式,则会先运算完成得到结果,再参与parseInt()函数的计算。
parseInt(15 * 3, 10); // 45 parseInt('15 * 3', 10); // 15 复制代码
- 对包含字符e的不同数据的处理差异
parseInt(6e3, 10) ; // 6000 parseInt(6e3, 16) ; // 24576 (6 * 16^3) parseInt('6e3', 10) ; // 6 ('e3'舍弃) parseInt('6e3', 16) ; // 1763 (6*16^2 + 14*16 + 3) 复制代码
- 对浮点型数的处理
如果传入的值是浮点型数,则会忽略小数点及后面的数,直接取整。
parseInt('6.01', 10) // 6 parseInt('6.99', 10) // 6 复制代码
- map()函数与parseInt()函数的隐形坑
设想一个场景,存在一个数组,数组中的每一个元素都是Number类型的字符串['1','2','3','4'],如果我们想要将数组中的元素全部转换为整数,我们该怎么做呢? 你可能会这样处理:
let arr = ['1','2','3','4']; let result = arr.map(parseInt); console.log(result); 复制代码
最终得到的结果确实[1,NaN,NaN,NaN]。 这其实是一个隐形坑,下面的两段代码其实是等效的。
arr.map(parseInt); arr.map((val, index)=> { return parseInt(val, index) }) 复制代码
parseInt()函数接受的第二个参数实际为数组的索引值,所以实际处理过程如下:
parseInt('1', 0); // 1 parseInt('2', 1); // NaN parseInt('3', 1); // NaN parseInt('4', 1); // NaN 复制代码
正确的处理方式应该是这样:
let arr = ['1','2','3','4']; let result = arr.map((val)=> { return parseInt(val, 10) }) console.log(result); // [1,2,3,4] 复制代码
3.parseFloat()函数
parseFloat()函数用于解析一个字符串,返回对应的浮点数,如果给定值不能转换为数值,则会返回“NaN”。
它与parseInt()函数相比,没有进制的概念,所以在转换时简单些,但是仍有一些需要注意的:
- 如果在解析过程中遇到了正负号、数字0~9、小数点或者科学计数法(e/E)以外的字符,则会忽略从该字符开始至结束的所有字符。其中,正负号必须出现在字符的第一位,而且不能连续出现。
parseFloat('+1.2'); // 1.2 parseFloat('++1.2'); // NaN 复制代码
- 字符串前面的空白符会直接忽略,如果第一个字符无法解析,直接返回“NaN”
parseFloat(' 1.2'); // 1.2 parseFloat('f1.2'); // NaN 复制代码
- 对于字符串中出现的e,会先进行科学计数法的运算,然后转换成浮点型数返回
parseFloat('4e3'); // 4000 复制代码
- 对于小数点,第二个小数点是无效的,后面的字符都会被忽略
parseFloat('11.20'); // 11.2 parseFloat('11.2.2'); // 11.2 复制代码
总结
这三个函数都能用于Number类型的转换,但是在处理方式上还是有一些差异的。
- Number()函数转换的是传入的整个值,整个值不能被完整转换,则会返回“NaN”。
- parseFloat()函数在解析小数点是,会把第一个小数点当作有效字符,而parseInt()函数遇到小数点则直接停止。
- parseFloat()函数在解析时没有进制的概念,而parseInt()函数在解析时会依赖于传入的基数做数值转换。