当前位置:  首页>> 技术小册>> Javascript重点难点实例精讲(一)

在实际的开发中,我们经常会遇到将其他类型的值转换为Number类型的情况。在JavaScript中,一共有3个函数可以完成这种转换,分别是Number()函数、parseInt()函数、parseFloat()函数,接下来就详细地讲解3个函数的使用方法与注意事项。

  1. Number()函数
    Number()函数可以用于将任何类型转换为Number类型,它在转换时遵循下列规则。
    ① 如果是数字,会按照对应的进制数据格式,统一转换为十进制并返回。
  1. Number(10); // 10
  2. Number(010); // 8,010是八进制的数据,转换成十进制是8
  3. Number(0x10); // 16,0x10是十六进制数据,转换成十进制是16

② 如果是Boolean类型的值,true将返回为“1”,false将返回为“0”。

  1. Number(true); // 1
  2. Number(false); // 0

③ 如果值为null,则返回“0”。

  1. Number(null); // 0

④ 如果值为undefined,则返回“NaN”。

  1. Number(undened); // NaN

⑤ 如果值为字符串类型,则遵循下列规则。
· 如果该字符串只包含数字,则会直接转换成十进制数;如果数字前面有0,则会直接忽略这个0。

  1. Number('21'); // 21
  2. Number('012'); // 12

· 如果字符串是有效的浮点数形式,则会直接转换成对应的浮点数,前置的多个重复的0会被清空,只保留一个。

  1. Number('0.12'); // 0.12
  2. Number('00.12'); // 0.12

· 如果字符串是有效的十六进制形式,则会转换为对应的十进制数值。如果字符串是有效的八进制形式,则不会按照八进制转换,而是直接按照十进制转换并输出,因为前置的0会被直接忽略。

  1. Number('010'); // 10
  2. Number('0020'); // 20

· 如果字符串为空,即字符串不包含任何字符,或为连续多个空格,则会转换为0。

  1. Number(''); // 0
  2. Number(' '); // 0

· 如果字符串包含了任何不是以上5种情况的其他格式内容,则会返回“NaN”。

  1. Number('123a'); // NaN
  2. Number('a1.1'); // NaN
  3. Number('abc'); // NaN

⑥ 如果值为对象类型,则会先调用对象的valueOf()函数获取返回值,并将返回值按照上述步骤重新判断能否转换为Number类型。如果都不满足,则会调用对象的toString()函数获取返回值,并将返回值重新按照步骤判断能否转换成Number类型。如果也不满足,则返回“NaN”。
以下是通过valueOf()函数将对象正确转换成Number类型的示例。

  1. var obj = {
  2. age: 21,
  3. valueOf: function () {
  4. return this.age;
  5. },
  6. toString: function () {
  7. return 'good';
  8. }
  9. };
  10. Number(obj); // 21

以下是通过toString()函数将对象正确转换成Number类型的示例。

  1. ar obj = {
  2. age: '21',
  3. valueOf: function () {
  4. return [];
  5. },
  6. toString: function () {
  7. return this.age;
  8. }
  9. };
  10. Number(obj); // 21

以下示例是通过valueOf()函数和toString()函数都无法将对象转换成Number类型的示例(最后返回“NaN”)。

  1. var obj = {
  2. age: '21',
  3. valueOf: function () {
  4. return 'a';
  5. },
  6. toString: function () {
  7. return 'b';
  8. }
  9. }
  10. Number(obj); // NaN

如果toString()函数和valueOf()函数返回的都是对象类型而无法转换成基本数据类型,则会抛出类型转换的异常。

  1. var obj = {
  2. age: '21',
  3. valueOf: function () {
  4. return [];
  5. },
  6. toString: function () {
  7. return [];
  8. }
  9. };
  10. Number(obj); // 抛出异常TypeError: Cannot convert object to primitive value
  1. parseInt()函数
    parseInt()函数用于解析一个字符串,并返回指定的基数对应的整数值。
    其语法格式如下。
  1. parseInt(string, radix);

其中string表示要被解析的值,如果该参数不是一个字符串,那么会使用toString()函数将其转换成字符串,而字符串前面的空白符会被忽略。
radix表示的是进制转换的基数,数据范围是2~36,可以是使用频率比较高的二进制、十进制、八进制和十六进制等,默认值为10。因为对相同的数采用不同进制进行处理时可能会得到不同的结果,所以在任何情况下使用parseInt()函数时,建议都手动补充第二个表示基数的参数。
parseInt()函数会返回字符串解析后的整数值,如果该字符串无法转换成Number类型,则会返回“NaN”。
在使用parseInt()函数将字符串转换成整数时,需要注意以下5点。
(1)非字符串类型转换为字符串类型
如果遇到传入的参数是非字符串类型的情况,则需要将其优先转换成字符串类型,即使传入的是整型数据。

  1. parseInt('0x12', 16); // 18
  2. parseInt(0x12, 16); // 24

第一条语句直接将字符串”0x12”转换为十六进制数,得到的结果为1×16+2=18;
第二条语句由于传入的是十六进制数,所以会先转换成十进制数18,然后转换成字符串”18”,再将字符串”18”转换成十六进制数,得到的结果为1×16+8=24。
(2)数据截取的前置匹配原则

parseInt()函数在做转换时,对于传入的字符串会采用前置匹配的原则。即从字符串的第一个字符开始匹配,如果处于基数指定的范围,则保留并继续往后匹配满足条件的字符,直到某个字符不满足基数指定的数据范围,则从该字符开始,舍弃后面的全部字符。在获取到满足条件的字符后,将这些字符转换为整数。

  1. parseInt("fg123", 16); // 15

对于字符串’fg123’,首先从第一个字符开始,’f’是满足十六进制的数据,因为十六进制数据范围是0~9,a~f(A~F),所以保留’f’;然后是第二个字符’g’,它不满足十六进制数据范围,因此从第二个字符至最后一个字符全部舍弃,最终字符串只保留字符’f’;然后将字符’f’转换成十六进制的数据,为15,因此最后返回的结果为“15”。
如果遇到的字符串是以”0x”开头的,那么在按照十六进制处理时,会计算后面满足条件的字符串;如果按照十进制处理,则会直接返回“0”。

  1. parseInt('0x12',16); // 18 = 16 + 2
  2. parseInt('0x12',10); // 0

需要注意的一点是,如果传入的字符串中涉及算术运算,则不执行,算术符号会被当作字符处理;如果传入的参数是算术运算表达式,则会先运算完成得到结果,再参与parseInt()函数的计算。

  1. parseInt(15 * 3, 10); // 45,先运算完成得到45,再进行parseInt(45, 10)的运算
  2. parseInt('15 * 3', 10); // 15,直接当作字符串处理,并不会进行乘法运算

(3)对包含字符e的不同数据的处理差异
处理的数据中包含字符e时,不同进制数的处理结果有很大不同。
当传入的参数本身就是Number类型时,会将e按照科学计数法计算后转换成字符串,然后按照对应的基数转换得到最终的结果。
如果传入的字符串中直接包含e,那么并不会按照科学计数法处理,而是会判断字符e是否处在可处理的进制范围内,如果不在则直接忽略,如果在则转换成对应的进制数。
以下为几行代码以及相应的执行结果。

  1. parseInt(6e3, 10); // 6000
  2. parseInt(6e3, 16); // 24576
  3. parseInt('6e3', 10); // 6
  4. parseInt('6e3', 16); // 1763

对于上述4个不同的结果,详细解释如下。
第一条语句parseInt(6e3, 10),首先会执行6e3=6000,然后转换为字符串”6000”,实际执行的语句是parseInt(‘6000’, 10),表示的是将字符串”6000”转换为十进制的整数,得到的结果为6000。
第二条语句parseInt(6e3, 16),首先会执行6e3=6000,然后转换为字符串”6000”,实际执行的语句是parseInt(‘6000’, 16),表示的是将字符串”6000”转换为十六进制的数,得到的结果是6×163 = 24576。
第三条语句parseInt(‘6e3’, 10),表示的是将字符串’6e3’转换为十进制的整数,因为字符’e’不在十进制所能表达的范围内,所以会直接省略,实际处理的字符串只有”6”,得到的结果为6。
第四条语句parseInt(‘6e3’, 16),表示的是将字符串’6e3’转换为十六进制的整数,因为字符’e’在十六进制所能表达的范围内,所以会转换为14进行计算,最后得到的结果为6×162 +14×16 + 3 = 1763。
(4)对浮点型数的处理
如果传入的值是浮点型数,则会忽略小数点及后面的数,直接取整。

  1. parseInt('6.01', 10); // 6
  2. parseInt('6.99', 10); // 6

经过上面的详细分析,我们再来看看以下语句的执行结果。以下语句都会返回“15”,这是为什么呢?

  1. parseInt("0xF", 16); // 十六进制的F为15,返回“15”
  2. parseInt("F", 16); // 十六进制的F为15,返回“15”
  3. parseInt("17", 8); // 八进制的"17",返回结果为1×8 + 7 = 15
  4. parseInt(021, 8); // 021先转换成十进制得到17,然后转换成字符串"17",再转换成
  5. // 八进制,返回结果为1×8 + 7 = 15
  6. parseInt("015", 10); // 前面的0忽略,返回“15”
  7. parseInt(15.99, 10); // 直接取整,返回“15”
  8. parseInt("15,123", 10); // 字符串"15,123"一一匹配,得到"15",转换成十进制后返回“15”
  9. parseInt("FXX123", 16); // 字符串"FXX123"一一匹配,得到"F",转换成十六进制后返回“15”
  10. parseInt("1111", 2); // 1×23 + 1×22 + 1×2 + 1 = 15
  11. parseInt("15 * 3", 10); // 字符串中并不会进行算术运算,实际按照"15"进行计算,返回“15”
  12. parseInt("15e2", 10); // 实际按照字符串"15"运算,返回“15”
  13. parseInt("15px", 10); // 实际按照字符串"15"运算,返回“15”
  14. parseInt("12", 13); // 按照十三进制计算,返回结果为1×13 + 2 = 15

(5)map()函数与parseInt()函数的隐形坑
设想这样一个场景,存在一个数组,数组中的每个元素都是Number类型的字符串[‘1’,’2’, ‘3’, ‘4’],如果我们想要将数组中的元素全部转换为整数,我们该怎么做呢?
我们可能会想到在Array的map()函数中调用parseInt()函数,代码如下。

  1. var arr = ['1', '2', '3', '4'];
  2. var result = arr.map(parseInt);
  3. console.log(result);

但是在运行后,得到的结果是[1, NaN, NaN, NaN],与我们期望的结果[1, 2, 3, 4]差别很大,这是为什么呢?
其实这就是一个藏在map()函数与parseInt()函数中的隐形坑。

  1. arr.map(parseInt);

上面的代码实际与下面的代码等效。

  1. arr.map(function (val, index) {
  2. return parseInt(val, index);
  3. });

parseInt()函数接收的第二个参数实际为数组的索引值,所以实际处理的过程如下所示。parseInt(‘1’, 0); // 1
parseInt(‘2’, 1); // NaN
parseInt(‘3’, 2); // NaN
parseInt(‘4’, 3); // NaN

  1. 任何整数以0为基数取整时,都会返回本身,所以第一行代码会返回“1”。
  2. 第二行代码parseInt('2', 1),因为parseInt()函数对应的基数只能为236,不满足基数的整数在处理后会返回“NaN”;
  3. 第三行代码parseInt('3', 2),表示的是将3处理为二进制表示,实际上二进制时只有013超出了二进制的表示范围,无法转换,返回“NaN”;
  4. 第四行代码parseInt('4', 3),与第三行类似,4无法用三进制的数据表示,返回“NaN”。
  5. 因此我们在map()函数中使用parseInt()函数时需要注意这一点,不能直接将parseInt()函数作为map()函数的参数,而是需要在map()函数的回调函数中使用,并尽量指定基数,代码如下所示。

var arr = [‘1’, ‘2’, ‘3’, ‘4’];

var result = arr.map(function (val) {
return parseInt(val, 10);
});

console.log(result); // [1, 2, 3, 4]

  1. 3. parseFloat()函数
  2. parseFloat()函数用于解析一个字符串,返回对应的浮点数。如果给定值不能转换为数值,则会返回“NaN”。
  3. parseInt()函数相比,parseFloat()函数没有进制的概念,所以在转换时会相对简单些,但是仍有以下一些需要注意的地方。
  4. 如果在解析过程中遇到了正负号(+ /
  5. ```)、数字0~9、小数点或者科学计数法(e / E)以外的字符,则会忽略从该字符开始至结束的所有字符,然后返回当前已经解析的字符的浮点数形式。
  6. 其中,正负号必须出现在字符的第一位,而且不能连续出现。

parseFloat(‘+1.2’); // 1.2
parseFloat(‘
```1.2’); //

  1. parseFloat('++1.2'); // NaN,符号不能连续出现
  2. parseFloat('

```1.2’); // NaN,符号不能连续出现
parseFloat(‘1+1.2’); // 1,’+’出现在第二位,不会当作符号位处理

  1. 字符串前面的空白符会直接忽略,如果第一个字符就无法解析,则会直接返回“NaN”。

parseFloat(‘ 1.2’); // 1.2
parseFloat(‘f1.2’); // NaN

  1. 对于字符串中出现的合法科学运算符e,进行运算处理后会转换成浮点型数,这点与parseInt()函数的处理有很大的不同。

parseFloat(‘4e3’); // 4000
parseInt(‘4e3’, 10); // 4
parseFloat()函数在处理’4e3’时,会先进行科学计数法的运算,即4e3 = 4×1000 = 4000,然后转换成浮点型数,返回“4000”;
parseInt()函数在以十进制处理’4e3’时,不会进行科学计数法的运算,而是直接从第一个字符开始匹配,最终匹配成功的字符为’4’,转换成整型后,返回整数“4”。
④ 对于小数点,只能正确匹配第一个,第二个小数点是无效的,它后面的字符也都将被忽略。

  1. parseFloat('11.20'); // 11.2
  2. parseFloat('11.2.1'); // 11.2

下面是使用parseFloat()函数的综合实例。

  1. parseFloat("123AF"); // 123,匹配字符串'123'
  2. parseFloat("0xA"); // 0,匹配字符串'0'
  3. parseFloat("22.5"); // 22.5,匹配字符串'22.5'
  4. parseFloat("22.3.56"); // 22.3,匹配字符串'22.3'
  5. parseFloat("0908.5"); // 908.5,匹配字符串'908.5'
  1. 结论
    虽然Number()、parseInt()和parseFloat()函数都能用于Number类型的转换,但是它们在处理方式上还是有一些差异的。
    · Number()函数转换的是传入的整个值,并不是像parseInt()函数和parseFloat()函数一样会从首位开始匹配符合条件的值。如果整个值不能被完整转换,则会返回“NaN”。
    · parseFloat()函数在解析小数点时,会将第一个小数点当作有效字符,而parseInt()函数在解析时如果遇到小数点会直接停止,因为小数点不是整数的一部分。
    · parseFloat()函数在解析时没有进制的概念,而parseInt()函数在解析时会依赖于传入的基数做数值转换

该分类下的相关小册推荐: