首页
技术小册
AIGC
面试刷题
技术文章
MAGENTO
云计算
视频课程
源码下载
PDF书籍
「涨薪秘籍」
登录
注册
第1章 JavaScript重点概念
1.1 JavaScript的基本数据类型介绍
1.2 Number类型详解
1.2.1 Number类型介绍
1.2.2 Number类型转换
1.2.3 isNaN()函数与Number.isNaN()函数对比
1.2.4 浮点型运算
1.3 String类型详解
1.3.1 String类型的定义与调用
1.3.2 String类型常见算法
1.4 运算符
当前位置:
首页>>
技术小册>>
Javascript重点难点实例精讲(一)
小册名称:Javascript重点难点实例精讲(一)
在实际的开发中,我们经常会遇到将其他类型的值转换为Number类型的情况。在JavaScript中,一共有3个函数可以完成这种转换,分别是Number()函数、parseInt()函数、parseFloat()函数,接下来就详细地讲解3个函数的使用方法与注意事项。 1. Number()函数 Number()函数可以用于将任何类型转换为Number类型,它在转换时遵循下列规则。 ① 如果是数字,会按照对应的进制数据格式,统一转换为十进制并返回。 ``` Number(10); // 10 Number(010); // 8,010是八进制的数据,转换成十进制是8 Number(0x10); // 16,0x10是十六进制数据,转换成十进制是16 ``` ② 如果是Boolean类型的值,true将返回为“1”,false将返回为“0”。 ``` Number(true); // 1 Number(false); // 0 ``` ③ 如果值为null,则返回“0”。 ``` Number(null); // 0 ``` ④ 如果值为undefined,则返回“NaN”。 ``` Number(undefined); // NaN ``` ⑤ 如果值为字符串类型,则遵循下列规则。 · 如果该字符串只包含数字,则会直接转换成十进制数;如果数字前面有0,则会直接忽略这个0。 ``` Number('21'); // 21 Number('012'); // 12 ``` · 如果字符串是有效的浮点数形式,则会直接转换成对应的浮点数,前置的多个重复的0会被清空,只保留一个。 ``` Number('0.12'); // 0.12 Number('00.12'); // 0.12 ``` · 如果字符串是有效的十六进制形式,则会转换为对应的十进制数值。如果字符串是有效的八进制形式,则不会按照八进制转换,而是直接按照十进制转换并输出,因为前置的0会被直接忽略。 ``` Number('010'); // 10 Number('0020'); // 20 ``` · 如果字符串为空,即字符串不包含任何字符,或为连续多个空格,则会转换为0。 ``` Number(''); // 0 Number(' '); // 0 ``` · 如果字符串包含了任何不是以上5种情况的其他格式内容,则会返回“NaN”。 ``` Number('123a'); // NaN Number('a1.1'); // NaN Number('abc'); // NaN ``` ⑥ 如果值为对象类型,则会先调用对象的valueOf()函数获取返回值,并将返回值按照上述步骤重新判断能否转换为Number类型。如果都不满足,则会调用对象的toString()函数获取返回值,并将返回值重新按照步骤判断能否转换成Number类型。如果也不满足,则返回“NaN”。 以下是通过valueOf()函数将对象正确转换成Number类型的示例。 ``` var obj = { age: 21, valueOf: function () { return this.age; }, toString: function () { return 'good'; } }; Number(obj); // 21 ``` 以下是通过toString()函数将对象正确转换成Number类型的示例。 ``` ar obj = { age: '21', valueOf: function () { return []; }, toString: function () { return this.age; } }; Number(obj); // 21 ``` 以下示例是通过valueOf()函数和toString()函数都无法将对象转换成Number类型的示例(最后返回“NaN”)。 ``` var obj = { age: '21', valueOf: function () { return 'a'; }, toString: function () { return 'b'; } } Number(obj); // NaN ``` 如果toString()函数和valueOf()函数返回的都是对象类型而无法转换成基本数据类型,则会抛出类型转换的异常。 ``` var obj = { age: '21', valueOf: function () { return []; }, toString: function () { return []; } }; Number(obj); // 抛出异常TypeError: Cannot convert object to primitive value ``` 2. parseInt()函数 parseInt()函数用于解析一个字符串,并返回指定的基数对应的整数值。 其语法格式如下。 ``` parseInt(string, radix); ``` 其中string表示要被解析的值,如果该参数不是一个字符串,那么会使用toString()函数将其转换成字符串,而字符串前面的空白符会被忽略。 radix表示的是进制转换的基数,数据范围是2~36,可以是使用频率比较高的二进制、十进制、八进制和十六进制等,默认值为10。因为对相同的数采用不同进制进行处理时可能会得到不同的结果,所以在任何情况下使用parseInt()函数时,建议都手动补充第二个表示基数的参数。 parseInt()函数会返回字符串解析后的整数值,如果该字符串无法转换成Number类型,则会返回“NaN”。 在使用parseInt()函数将字符串转换成整数时,需要注意以下5点。 (1)非字符串类型转换为字符串类型 如果遇到传入的参数是非字符串类型的情况,则需要将其优先转换成字符串类型,即使传入的是整型数据。 ``` parseInt('0x12', 16); // 18 parseInt(0x12, 16); // 24 ``` 第一条语句直接将字符串"0x12"转换为十六进制数,得到的结果为1×16+2=18; 第二条语句由于传入的是十六进制数,所以会先转换成十进制数18,然后转换成字符串"18",再将字符串"18"转换成十六进制数,得到的结果为1×16+8=24。 (2)数据截取的前置匹配原则 parseInt()函数在做转换时,对于传入的字符串会采用前置匹配的原则。即从字符串的第一个字符开始匹配,如果处于基数指定的范围,则保留并继续往后匹配满足条件的字符,直到某个字符不满足基数指定的数据范围,则从该字符开始,舍弃后面的全部字符。在获取到满足条件的字符后,将这些字符转换为整数。 ``` parseInt("fg123", 16); // 15 ``` 对于字符串'fg123',首先从第一个字符开始,'f'是满足十六进制的数据,因为十六进制数据范围是0~9,a~f(A~F),所以保留'f';然后是第二个字符'g',它不满足十六进制数据范围,因此从第二个字符至最后一个字符全部舍弃,最终字符串只保留字符'f';然后将字符'f'转换成十六进制的数据,为15,因此最后返回的结果为“15”。 如果遇到的字符串是以"0x"开头的,那么在按照十六进制处理时,会计算后面满足条件的字符串;如果按照十进制处理,则会直接返回“0”。 ``` parseInt('0x12',16); // 18 = 16 + 2 parseInt('0x12',10); // 0 ``` 需要注意的一点是,如果传入的字符串中涉及算术运算,则不执行,算术符号会被当作字符处理;如果传入的参数是算术运算表达式,则会先运算完成得到结果,再参与parseInt()函数的计算。 ``` parseInt(15 * 3, 10); // 45,先运算完成得到45,再进行parseInt(45, 10)的运算 parseInt('15 * 3', 10); // 15,直接当作字符串处理,并不会进行乘法运算 ``` (3)对包含字符e的不同数据的处理差异 处理的数据中包含字符e时,不同进制数的处理结果有很大不同。 当传入的参数本身就是Number类型时,会将e按照科学计数法计算后转换成字符串,然后按照对应的基数转换得到最终的结果。 如果传入的字符串中直接包含e,那么并不会按照科学计数法处理,而是会判断字符e是否处在可处理的进制范围内,如果不在则直接忽略,如果在则转换成对应的进制数。 以下为几行代码以及相应的执行结果。 ``` parseInt(6e3, 10); // 6000 parseInt(6e3, 16); // 24576 parseInt('6e3', 10); // 6 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)对浮点型数的处理 如果传入的值是浮点型数,则会忽略小数点及后面的数,直接取整。 ``` parseInt('6.01', 10); // 6 parseInt('6.99', 10); // 6 ``` 经过上面的详细分析,我们再来看看以下语句的执行结果。以下语句都会返回“15”,这是为什么呢? ``` parseInt("0xF", 16); // 十六进制的F为15,返回“15” parseInt("F", 16); // 十六进制的F为15,返回“15” parseInt("17", 8); // 八进制的"17",返回结果为1×8 + 7 = 15 parseInt(021, 8); // 021先转换成十进制得到17,然后转换成字符串"17",再转换成 // 八进制,返回结果为1×8 + 7 = 15 parseInt("015", 10); // 前面的0忽略,返回“15” parseInt(15.99, 10); // 直接取整,返回“15” parseInt("15,123", 10); // 字符串"15,123"一一匹配,得到"15",转换成十进制后返回“15” parseInt("FXX123", 16); // 字符串"FXX123"一一匹配,得到"F",转换成十六进制后返回“15” parseInt("1111", 2); // 1×23 + 1×22 + 1×2 + 1 = 15 parseInt("15 * 3", 10); // 字符串中并不会进行算术运算,实际按照"15"进行计算,返回“15” parseInt("15e2", 10); // 实际按照字符串"15"运算,返回“15” parseInt("15px", 10); // 实际按照字符串"15"运算,返回“15” parseInt("12", 13); // 按照十三进制计算,返回结果为1×13 + 2 = 15 ``` (5)map()函数与parseInt()函数的隐形坑 设想这样一个场景,存在一个数组,数组中的每个元素都是Number类型的字符串['1','2', '3', '4'],如果我们想要将数组中的元素全部转换为整数,我们该怎么做呢? 我们可能会想到在Array的map()函数中调用parseInt()函数,代码如下。 ``` var arr = ['1', '2', '3', '4']; var result = arr.map(parseInt); console.log(result); ``` 但是在运行后,得到的结果是[1, NaN, NaN, NaN],与我们期望的结果[1, 2, 3, 4]差别很大,这是为什么呢? 其实这就是一个藏在map()函数与parseInt()函数中的隐形坑。 ``` arr.map(parseInt); ``` 上面的代码实际与下面的代码等效。 ``` arr.map(function (val, index) { return parseInt(val, index); }); ``` parseInt()函数接收的第二个参数实际为数组的索引值,所以实际处理的过程如下所示。parseInt('1', 0); // 1 parseInt('2', 1); // NaN parseInt('3', 2); // NaN parseInt('4', 3); // NaN ``` 任何整数以0为基数取整时,都会返回本身,所以第一行代码会返回“1”。 第二行代码parseInt('2', 1),因为parseInt()函数对应的基数只能为2~36,不满足基数的整数在处理后会返回“NaN”; 第三行代码parseInt('3', 2),表示的是将3处理为二进制表示,实际上二进制时只有0和1,3超出了二进制的表示范围,无法转换,返回“NaN”; 第四行代码parseInt('4', 3),与第三行类似,4无法用三进制的数据表示,返回“NaN”。 因此我们在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] ``` 3. parseFloat()函数 parseFloat()函数用于解析一个字符串,返回对应的浮点数。如果给定值不能转换为数值,则会返回“NaN”。 与parseInt()函数相比,parseFloat()函数没有进制的概念,所以在转换时会相对简单些,但是仍有以下一些需要注意的地方。 ① 如果在解析过程中遇到了正负号(+ / ```)、数字0~9、小数点或者科学计数法(e / E)以外的字符,则会忽略从该字符开始至结束的所有字符,然后返回当前已经解析的字符的浮点数形式。 其中,正负号必须出现在字符的第一位,而且不能连续出现。 ``` parseFloat('+1.2'); // 1.2 parseFloat(' ```1.2'); // ```1.2 parseFloat('++1.2'); // NaN,符号不能连续出现 parseFloat(' ``` ```1.2'); // NaN,符号不能连续出现 parseFloat('1+1.2'); // 1,'+'出现在第二位,不会当作符号位处理 ``` ② 字符串前面的空白符会直接忽略,如果第一个字符就无法解析,则会直接返回“NaN”。 ``` parseFloat(' 1.2'); // 1.2 parseFloat('f1.2'); // NaN ``` ③ 对于字符串中出现的合法科学运算符e,进行运算处理后会转换成浮点型数,这点与parseInt()函数的处理有很大的不同。 ``` parseFloat('4e3'); // 4000 parseInt('4e3', 10); // 4 parseFloat()函数在处理'4e3'时,会先进行科学计数法的运算,即4e3 = 4×1000 = 4000,然后转换成浮点型数,返回“4000”; parseInt()函数在以十进制处理'4e3'时,不会进行科学计数法的运算,而是直接从第一个字符开始匹配,最终匹配成功的字符为'4',转换成整型后,返回整数“4”。 ④ 对于小数点,只能正确匹配第一个,第二个小数点是无效的,它后面的字符也都将被忽略。 ``` parseFloat('11.20'); // 11.2 parseFloat('11.2.1'); // 11.2 ``` 下面是使用parseFloat()函数的综合实例。 ``` parseFloat("123AF"); // 123,匹配字符串'123' parseFloat("0xA"); // 0,匹配字符串'0' parseFloat("22.5"); // 22.5,匹配字符串'22.5' parseFloat("22.3.56"); // 22.3,匹配字符串'22.3' parseFloat("0908.5"); // 908.5,匹配字符串'908.5' ``` 4. 结论 虽然Number()、parseInt()和parseFloat()函数都能用于Number类型的转换,但是它们在处理方式上还是有一些差异的。 · Number()函数转换的是传入的整个值,并不是像parseInt()函数和parseFloat()函数一样会从首位开始匹配符合条件的值。如果整个值不能被完整转换,则会返回“NaN”。 · parseFloat()函数在解析小数点时,会将第一个小数点当作有效字符,而parseInt()函数在解析时如果遇到小数点会直接停止,因为小数点不是整数的一部分。 · parseFloat()函数在解析时没有进制的概念,而parseInt()函数在解析时会依赖于传入的基数做数值转换
上一篇:
1.2.1 Number类型介绍
下一篇:
1.2.3 isNaN()函数与Number.isNaN()函数对比
该分类下的相关小册推荐:
npm script实战构建前端工作流
JavaScript入门与进阶
经典设计模式Javascript版
Flutter核心技术与实战
WebSocket入门与案例实战
KnockoutJS入门指南
剑指javascript-ES6
编程入门课:Javascript从入门到实战
剑指javascript
Javascript-ES6与异步编程
javascript设计模式原理与实战
ES6入门指南