第04章 数值类型

398 阅读11分钟

一、概述

数值型作为JavaScript中一个基本数据类型在程序中是不可或缺的,程序中的逻辑实现、条件判断都直接或间接地需要数值才能实现。比如说对数组的操作,循环语句的实现,没有数值型这种数据类型是办不到的。当然,这只是指这种数据类型在程序中的运用。谈到实际的项目,像金融这一类的网站或应用,如果对数值型这个数据类型没有充分的了解,做出的成品是很难有质量保证的,其所表示的数据准确性也会饱受怀疑,在对互联网软件产品质量要求越来越高的今天,这样的产品是达不到上线要求的。

在JavaScript中,所有的数字都是以 64位**浮点数(小数)**的形式存储的,就算是表面上看到的是一个整数,实质上它也是一个浮点数。如“1”和“1.0”完全是同一个数,执行“1 === 1.0 ”会返回“true”的布尔值。其实在JavaScript语言的底层,根本没有整数(其他编程语言是“int”型)这个类型 。但有的时候JavaScript的值的计算必须要整数才能完成,JavaScript的做法也只是将它64位的数值转换为32位再进行运算而已。

二、数值型的精度问题

浮点数始终是一个不精确的数,在进行浮点数运算的时候会出现一些意料外的情况。比如现在我们拿以下几个浮点数在控制台内进行运算输出,观察结果:

0.1 + 0.2 === 0.3; // false

0.1 + 0.2; // 0.30000000000000004
0.3 / 0.1; // 2.9999999999999996
0.3 - 0.2; // 0.09999999999999998

所以,在进行一些需要高精度的整数计算的时候,最好能对运算数使用保留小数点的方法“toFixed()”,再用对应的十分位数相乘转换回原始计算结果,该方法的括号内需要有一个参数,参数是一个数值型,如toFixed(2)”表示计算结果保留两位小数,然后将得出的结果乘以“100”即会得到一个相对精确的整数。

根据IEEE 754规定,JavaScript能精确表示的数值范围在 (2531)-(2^{53} - 1)25312^{53}-1 之间。在JavaScript中对数值求幂(N次方)的函数是:

Math.pow(binary,power)

其中 binary 是指“底数”,函数中的参数意思就是“binary”的“power”次幂(次方),如“Math.pow(5,3)”得出的结果就是125,表示5的3次方。所以,针对上述原理,我们可以算出JavaScript最大能保留的精度数值,写作:Math.pow(2,53)。我们在控制台内做这样一个实验:

part_3_1.jpeg

从上面示例可以看到,大于2的53次方以后,整数运算的结果开始出现错误。所以,大于等于2的53次方的数值,都无法保持精度。而且大于该值位数的值都不能被保存,被会自动省略掉。

JavaScript还能采用科学计数法来表示一个数值,将数字写在“e”或“E”后方表示指数,如:

123e2  //  12300
-123e2  // -12300

 0.0314e2 //  3.14
-0.0314e2 // -3.14

有两种情况,JavaScript会将一个数值自动转换为科学计数法,一种是小数点前多于21位的数字,另外一种是小数点后的“0”多于5位的情况,如:

part_3_2.jpeg

三、NaN *

1、含义

在数值型数据中,有一个特殊值 NaN,它表示的是 “非数字”( Not a Number),主要出现在将字符串解析成数字出错的场合。

Number("x");
NaN

上面代码运行时,会自动将字符串x转为数值,但是由于x不是数值,所以最后得到结果为 NaN,表示它是“非数字”。

另外,一些数学函数及运算操作的结果会出现 NaN

part_3_3.jpeg

需要注意的是,NaN 不是一种独立的数据类型,而是一种特殊数值,它的数据类型依然属于Number,使用 typeof 运算符可以查看数据类型。

typeof NaN;
"number"

2、运算规则

  1. NaN 不等于任何值,包括它本身。
NaN === NaN; // false
  1. NaN 在布尔运算时被当作 false
Boolean(NaN); // false 

3. NaN 与任何数(包括它自己)的运算,得到的都是 NaN

NaN + 32; // NaN
NaN - 32; // NaN
NaN * 32; // NaN
NaN / 32; // NaN

3、判断NaN的方法

要判断一个数据的值是否是“NaN”,JavaScript提供了一个方法:isNaN(param),将需要判断的值或变量作为参数放置于该方法内,即可根据返回的值判断该值或变量是否为一个“NaN”,该方法的返回值是一个布尔值,如果返回的值为true,表示值为NaN,如果返回的值为false,那就表示它的值不是NaN,如例:

part_3_4.jpeg

可以发现,其实直接对值类型进行判断的情况下,除了数值型以外,返回的结果都是true,当然也包括它自身isNaN(NaN),得出的结果同样是true。NaN产生的条件是:当参与算术运算中的某个值不为数值型的值,那返回的结果就会为NaN。但“+”运算符比较特殊,因为有的时候它是可以作为字符串拼接运算符的。观察控制台中输出的结果:

part_3_5.jpeg

四、数值转换 *

在实际的数值获取中,很多时候取到的数值并非是以数值存在的。如:字符串*"3",像素单位"30px",单个数组元素 [30] 等,这些类型的值在参与和数值型算术运算时会产生意外的结果,如,一个数值在和一个字符串、像素单位值或单个数组进行“+*”运算时,起到的是一个“字符串拼接”的作用,而在执行“-”、“×”或“÷”运算时又是进行基本算术运算。如例:

part_3_6.jpeg

当然,上面这些“非数值”的内容都还是一个数值内容,能通过程序自动转换的情况。倘若取到的值是一个带单位的,情况又有所不同了:

part_3_7.jpeg

在数值转换中,除了自动转换,还包括下面几个转换方法:

1、parseInt()

作用:转换结果为整数

转换规则:从左往右依次转换,直到遇到非数字字符为止。

part_3_11.jpeg

提示:

  1. parseInt 转换结果不是十进制数 就是NaN
  2. parseInt 能转换数组首元素

parseInt 不能转换科学计数法,在转换科学计数法的数字时,会省略e后面的内容:

parseInt("314e-2") // 314
parseInt("21e3")   // 21

2、parseFloat()

作用:转换结果为浮点数

转换规则:从左往右依次转换,直到遇到非数字字符为止。

parseFloat('20.25')   // 20.25
parseFloat(['20.25']) // 20.25
parseFloat('20.25e2') // 2025
parseFloat('1234e-2') // 12.34
parseFloat('3.14abc') // 3.14
parseFloat('   3.14')  // 3.14

parseFloat('A2') // NaN
parseFloat('[]') // NaN
parseFloat('  ') // NaN

3、Number()

作用:将转换对象转换为数字(自动转换采用该方式)

转换规则:整体转换,只要转换对象中包含非数字字符则结果为NaN

Number("1");    // 1
Number("3.14"); // 3.14
Number("12e2"); // 1200
Number("3x14"); // NaN

五、数值进制

作为一门计算机语言,JavaScript自然也支持四种基本的进制表示法,它们分别是:十进制、二进制、八进制和十六进制。

1、十进制

日常生活中的数字

2、二进制

需要在数值之前加上前导数:“0b”或“0B”,且前导数后方的数值不能大于1,或是其它内容,否则浏览器会报错,如:

part_3_8.jpeg

3、八进制

需要在数值之前加上前导数:“0o”或“0O”,且前导数后方的数值不能大于7,或是其它内容,否则浏览器会报错容,如:

part_3_9.jpeg

4、十六进制

需要在数值之前加上前导数:“0x”或“0X”,且前导数后方的数值不能大于fF(相当于十进制内的15),或是其它内容,否则浏览器会报错,如:

part_3_10.jpeg

六、进制转换

通过 parseInt 方法,可以将任意进制数转换为十进制数。但当需要转换的进制数为一个字符串时,该方法只能对十六进制的数进行正确的转换。

parseInt(0b1010)   // 10
parseInt(0o12)   // 10
parseInt(0xA)  // 10

parseInt("0b1010") // 异常 ‘0’
parseInt("0o12") // 异常 ‘0’
parseInt("0xA") // 10

但我们在实际的项目操作中获取到的进制数大多是以字符串的形式存在的,这里我们可以使用 parseInt 的第二个参数,该参数可以告诉该方法需要转换的字符是何种进制的,并将其转换为十进制的数。需要注 意的是,如果配置了第二个参数,那第一个参数就不能包含前导数了,否则除了十六进制会出现异常。

parseInt("1010", 2);
10
parseInt("0b1010", 2);
0 // 异常
parseInt("12", 8);
10
parseInt("0o12", 8);
0 // 异常
parseInt("A", 16);
10
parseInt("0xA", 16);
10

parseInt 方法的第二个参数除了上述几种形式之外还可以为其他进制数,它的范围是2~36之间的数值,只有在这个范围内才会返回有意义的数值,如果超出这个范围则会返回NaN

parseInt("11", 2)  // 二进制 3
parseInt("11", 3)  // 三进制 4
parseInt("11", 4)  // 四进制 5
parseInt("11", 36) // 三十六进制 37

parseInt("11", 1)  // 一进制,异常
parseInt("11", 37) // 三十七进制,异常

上面提到的,是将各种进制数转换为十进制数,有时你可能想将一个十进制数转换为其他进制数,这时我们可以使用 toString() 方法,括号里面的参数为转换到的进制,如下所示:

(10).toString(2)  // "1010"
(10).toString(8)  // "12"
(10).toString(16) // "a"

七、数值对象

1、简介

Number 对象是数值对应的包装对象,可以作为构造函数使用,也可以作为工具函数使用。

 // 1、构造函数使用,生成数值对象
var n = new Number(1); // 1
typeof n; // "object"

// 2、工具函数使用,类型转换
Number('3.14'); // 3.14

2、属性

属性描述
Number.MAX_VALUE可表示的最大值
Number.MIN_VALUE可表示的最小值
Number.NaN特指”非数字“
Number.NEGATIVE_INFINITY特指“负无穷”;在溢出时返回
Number.POSITIVE_INFINITY特指“正无穷”;在溢出时返回
Number.EPSILON表示1和比最接近1且大于1的最小Number之间的差别
Number.MIN_SAFE_INTEGERJavaScript最小安全整数.
Number.MAX_SAFE_INTEGERJavaScript最大安全整数.

提示:了解

3、方法 *

1)、toString() *

toString() 方法用于将数值转为字符串

var n = 3.14;
n.toString();      // "3.14"

(101).toString();  // "101"
(3.2).toString();  // "3.2"

toString 方法可以接受一个参数,表示输出的进制。如果省略这个参数,默认将数值先转为十进制,再输出字符串;否则,就根据参数指定的进制,将一个数字转化成某个进制的字符串。

(10).toString(2)  // "1010"
(10).toString(8)  // "12"
(10).toString(16) // "a"

上面代码中,之所以要把10放在括号里,是为了表明10是一个单独的数值,后面的点表示调用对象属性。如果不加括号,这个点会被JavaScript引擎解释成小数点,从而报错。

10.toString(2)
// SyntaxError: Unexpected token ILLEGAL

只要能够让JavaScript引擎不混淆小数点和对象的点运算符,各种写法都能用,一般建议使用括号() 区分。

10..toString()  // "10"
10 .toString()  // "10"
10.0.toString() // "10"
(10).toString() // "10"

2)、toFixed() *

toFixed 方法用于将一个数转为指定位数的小数,返回这个小数对应的字符串。

(10).toFixed(2) // "10.00"

(3.1415926).toFixed(2) // "3.14"
(3.1415926).toFixed(3) // "3.141"

3)、toExponential()

toExponential 方法用于将一个数转为科学计数法形式。该方法的参数表示小数点后有效数字的位数,范围为0到20,超出这个范围,会抛出一个RangeError。

(12345).toExponential(1);
"1.2e+4"
(12345).toExponential(2);
"1.23e+4"
(12345).toExponential(3);
"1.235e+4"
(12345).toExponential(4);
"1.2345e+4"

4)、toPrecision()

toPrecision方法用于将一个数转为指定位数的有效数字。

(123).toPrecision(1);
"1e+2"
(123).toPrecision(2);
"1.2e+2"
(123).toPrecision(3);
"123"
(123).toPrecision(4);
"123.0"
(123).toPrecision(5);
"123.00"

toPrecision 方法用于四舍五入时不太可靠,跟浮点数不是精确储存有关。

(3.1415926).toPrecision(1) // 3
(3.1415926).toPrecision(2) // 3.1
(3.1415926).toPrecision(3) // 3.14
(3.1415926).toPrecision(4) // 3.141

八、课后练习

实现一个简易计算器