黄子涵

3.4 数值型

3.4.1 数值字面量

在 JavaScript 中,数值的内部结构为 64 位的浮点小数。不过在实际的编程中,使用整数的情况会更多。不管内部构造如何,从 JavaScript 的代码上来看,只要是写为整数就能够作为整数使用,而不必考虑是否是浮点数的问题。因为所有的数值都是浮点小数,所以其运行效率多少会有些下降。因此对于比较注重运行效率的程序来说,JavaScript 可能并不是合适的选择。

由于整数型和浮点数型在使用上没有差别,所以不会发生和类型转换相关的错误。当然,浮点小数本身所具有的缺点依然存在。不过对于大部分现代程序设计语言来说,如果要使用小数,这些问题还是难以避免。

image

// 下面是使用数值字面量的代码示例
// 将数值1赋值给变量hzh1
var hzh1 = 1;
// 将数值2赋值给变量hzh2
var hzh2 = 2;
// 将变量hzh1的值域变量hzh2的值相加
console.log("输出hzh1和hzh2的和:");
console.log(hzh1 + hzh2);
console.log("*********************************************");
// 可以通过 typeof 运算符来判断数值的类型。
// 对于数值来说,typeof 运算符返回的结果是字符串值 "number"。
var hzh3 = 1;
// 对数值进行typeof运算
console.log("输出hzh3的数据类型:");
console.log(typeof hzh3);
// 对数值字面量进行typeof运算
console.log("输出1的数据类型:");
console.log(typeof 1);

image

3.4.2 数值型的运算

对于数值可以进行 +(加法)、-(减法)、*(乘法)、/(除法)四则运算。通过 % 符号则可以进行求模运算(即计算除法运算后的余数)。

需要注意的是,尽管从代码上来看进行的是整数运算,但其实在其内部进行的仍然是浮点数运算。例如,对 0 作除法并不会得到错误的结果,而是会得到一个特殊的数值。

var hzh1 = 1;
var hzh2 = 2;
console.log("输出1除以0的结果:");
console.log(hzh1/0);
console.log("输出2除以0的结果:");
console.log(hzh2/0);

image

在 JavaScript 标准对象中有一个 Math 对象。该对象定义了圆周率 PI、自然对数的底数 E 等数学常量,以及一些相关的数学函数。例如,可以通过 Math.pow 函数计算 2 的 10 次方。

var hzh1 = Math;
console.log("打印圆周率的e");
console.log(hzh1.E);
console.log("打印圆周率的PI");
console.log(hzh1.PI);
console.log("计算2的10次方:");
console.log(hzh1.pow(2,10));

image

3.4.3 有关浮点数的常见注意事项

// 对于浮点数来说,有时候并不能正确地表达小数点以后的部分。
// 实际上,能够正确表达一个数的值反而是一种例外,
// 大部分情况下浮点数只能表达数值的近似值
console.log("计算0.1和0.2的和:");
console.log(0.1 + 0.2);
console.log("判断0.1和0.2的和是否与0.3相等?");
console.log((0.1 + 0.2) == 0.3);
console.log("判断0.1和0.2的和是否与0.3严格相等?");
console.log((0.1 + 0.2) === 0.3);
console.log("输出1/3的值:");
console.log(1/3);
console.log("输出(10/3)-3的值:");
console.log((10/3)-3);
console.log("判断((10/3)-3)是否与1/3相等?");
console.log(((10/3)-3) == (1/3));
console.log("判断((10/3)-3)是否与1/3严格相等?");
console.log(((10/3)-3) === (1/3));

image

对于浮点数来说,要执行正确的实数运算是不可能的。稍加注意就会发现,这并不是个应该如何避免的问题,而是从原理上就是无法回避的。对于整数的情况,则可以保证在 53 位的范围内能有正确的结果。因此,如果只是使用 53 位以内的整数的话,就不会有任何问题。

如果需要用到数值正确的实数,就必须使用类似于 Java 中的 BigDecimal 类的实数库。目前,JavaScript 并没有标准的实数库。不过也有特殊情况,如果是在 JVM 下使用 Rhino(一种基于 Java 的开源 JavaScript 实现)的话,就能够直接使用 Java的 BigDecimal 类了。

3.4.4 数值类(Number 类)

正如存在字符串类(String 类),JavaScript 中也存在数值类(Number 类)。字符串值和字符串类在经过隐式数据类型转换之后,就基本能够以相同的方式使用,与此类似,经过数据类型转换之后,数值和数值对象也能被视为等价的。

// 为了区分小数点和点运算符而必须使用括号
var hzh1 = (1).toString();
console.log("输出(1).toString()的值:");
console.log(hzh1);
// 确认是否确实是从数值转换为了字符串
console.log("判断(1).toString()的数据类型:");
console.log(typeof hzh1);
console.log("***************************************************");
// 由于会进行隐式数据类型转换,因此数值和数值对象在外表上是没有什么区别的
// 如有必要,可以通过 typeof 运算对其进行判断
// 对数值对象执行 typeof 运算的结果为 "object"
var hzh2 = new Number(1);
console.log("判断Number(1)的数据类型:");
console.log(typeof hzh2);

image

3.4.5 调用 Number 函数

// 和 String 函数类似,以通常的方式调用 Number 函数的话,将返回相应的数值。
// 在需要显式地进行数据类型转换的时候,可以使用 Number 函数。
var hzh1 = Number(1);
// 变量hzh1的值为数值
console.log("判断Number(1)的数据类型:");
console.log(typeof hzh1);
console.log("判断hzh1和1是否相等:");
console.log(hzh1 == 1);
console.log("判断hzh1和1是否严格相等:");
console.log(hzh1 === 1);
console.log("*****************************************************");
// 从字符串值至数值型的显式数据类型转换
var hzh2 = Number('1');
console.log("输出Number('1')的结果:");
console.log(hzh2);
console.log("*****************************************************");
// 如果参数无法被转换为数值类型,Number 函数返回的结果将是 NaN
var hzh3 = Number('x');
console.log("输出Number('x')的结果:");
console.log(hzh3);
console.log("判断Number('x')的数据类型:");
console.log(typeof hzh3);
console.log("*****************************************************");
var hzh4 = new Number('x');
console.log("输出new Number('x')的结果:");
console.log(hzh4);
console.log("判断new Number('x')的数据类型:");
console.log(typeof hzh4);

image

3.4.6 Number 类的功能

Number 类的函数以及构造函数调用

image

Number 类的属性

image

Number.prototype 对象的属性

image

Number 类的实例属性

image

3.4.7 边界值与特殊数值

// 可以通过 Number 对象的属性值来获知 64 位浮点数所支持的最大正值和最小正值
// 如果在其之前添加负号(运算符),就能够获得相应的最大负值和最小负值
var hzh1 = Number.MAX_VALUE;
var hzh2 = Number.MIN_VALUE;
var hzh3 = - Number.MAX_VALUE;
var hzh4 = - Number.MIN_VALUE;
console.log("输出Number.MAX_VALUE的结果:");
console.log(hzh1);
console.log("输出Number.MIN_VALUE的结果:");
console.log(hzh2);
console.log("输出- Number.MAX_VALUE的结果:");
console.log(hzh3);
console.log("输出- Number.MIN_VALUE的结果");
console.log(hzh4);
console.log("*******************************************************");
// 还可以通过 Number.MAX_VALUE.toString(16) 来获得相应的 16 进制数值
var hzh5 = Number.MAX_VALUE.toString(16);
console.log("输出Number.MAX_VALUE.toString(16)的结果:");
console.log(hzh5);

image

浮点小数的特殊数值

image

// 在 JavaScript 中,浮点数的内部结构遵循 IEEE754 标准。
// 可以通过 Number 对象的属性值来获得在 IEEE754 中定义的一些特殊数值。
var hzh6 = Number.POSITIVE_INFINITY;
var hzh7 = Number.NEGATIVE_INFINITY;
var hzh8 = Number.NaN;
console.log("输出Number.POSITIVE_INFINITY的结果:");
console.log(hzh6);
console.log("输出Number.NEGATIVE_INFINITY的结果:");
console.log(hzh7);
console.log("输出Number.NaN的结果");
console.log(hzh8);

image

从内部结构来看,这 3 个特殊数值(即正负无穷大与 NaN)都是基于 IEEE754 标准的比特位数值。虽然它们在形式上属于数值(typeof 运算符对它们的执行结果为 number),但是并不能作为数值进行计算。例如,将最大正数值乘以 2 之后能够得到正无穷大,但反之则不成立,正无穷大除以 2 之后无法得到最大正数值。

事实上,这 3 个特殊数值对于任何运算都无法得到通常的数值结果。

var hzh1 =  Number.MAX_VALUE * 2;
console.log("输出hzh1的结果:");
console.log(hzh1);   // 将最大正数值乘以2之后能够得到正无穷大
console.log("输出(hzh1/2)的结果:");
console.log(hzh1/2); // 再除以2之后却无法得到原值
console.log("输出(hzh1*0)的结果:");
console.log(hzh1*0); // 即使乘以0,得到的结果也不是0

image

3.4.8 NaN

// 对 NaN 进行任何运算,其结果都是 NaN。
// 因此,如果在计算过程中出现了一次 NaN,
// 最终的结果就一定会是 NaN
console.log("输出(NaN + 1)的结果:");
console.log(NaN + 1);
console.log("输出(NaN*0)的结果:");
console.log(NaN * 0);
console.log("输出(NaN - NaN)的结果:");
console.log(NaN - NaN);
console.log("*****************************************");
// NaN 不但不与其他任何数值相等,
// 就算是两个 NaN 的等值判断,其结果也为假
console.log("输出(NaN == 1)的结果:");
console.log(NaN == 1);
console.log("输出(NaN === 1)的结果:");
console.log(NaN === 1);
console.log("输出(NaN == NaN)的结果:");
console.log(NaN == NaN);
console.log("输出(NaN === NaN)的结果:");
console.log(NaN === NaN);
console.log("*****************************************");
console.log("输出(NaN > 1)的结果:");
console.log(NaN > 1);
console.log("输出(NaN >= 1)的结果:");
console.log(NaN >= 1);
console.log("输出(NaN > NaN)的结果:");
console.log(NaN > NaN);
console.log("输出(NaN >= NaN)的结果:");
console.log(NaN >= NaN);

image

// JavaScript 中预定义了一个全局函数 isNaN。
// isNaN 函数的返回值为真的条件是其参数的值为 NaN,
// 或是在经过数据类型转换至数值类型后值为 NaN。
console.log("使用isNaN判断NaN:");
console.log(isNaN(NaN));
// NaN值的Number对象
var hzh1 = new Number(NaN);
console.log("判断hzh1的数据类型:");
console.log(typeof hzh1);
console.log("使用isNaN判断hzh1:");
console.log(isNaN(hzh1));
console.log("使用isNaN判断{}:");
console.log(isNaN({}));
console.log("*****************************************");
// 而预定义全局函数 isFinite 可以对 3 个特殊数值
// (即 NaN与正负无穷大)之外的数值进行判断
console.log("使用isFinite判断数值1:");
console.log(isFinite(1));
console.log("使用isFinite判断数值NaN:");
console.log(isFinite(NaN));
console.log("使用isFinite判断数值Infinity:");
console.log(isFinite(Infinity));
console.log("使用isFinite判断数值-Infinity:");
console.log(isFinite(-Infinity));

image

可以得到浮点数特殊数值的运算

image

// 在 ECMAScript 第 5 版中,已将 NaN 和 Infinity 改为了只读变量,
// 因此不能再对它们进行数值更改。
// 需要注意的是,在对它们进行赋值的过程中并不会报错。
console.log("输出NaN:");
NaN = 7;
console.log(NaN);
console.log("输出Infinity:");
Infinity = 8; 
console.log(Infinity);

image

posted @ 2022-05-26 08:58  黄子涵  阅读(152)  评论(0编辑  收藏  举报