数值类型 Number

JavaScript 只有一种数字类型,它在内部被表示为 64 位的浮点数,和 Java 的 double 数字类型一样。

与其他大多数编程语言不同的是,它没有分离出整数类型,所以 1 和 1.0 的值相同,这提供了很大的方便,避免了一大堆因数字类型导致的错误。数值类型 Number 是 JS 中的原始数据类型,同时 JS 也支持 Number 对象(一个原始数值的包装对象)。在需要时,JS 会自动在原始形式和对象形式之间转换。


定义方式

JavaScript 采用 IEEE754 格式来表示数字,不区分整数和浮点数,JS 中的所有数字都用浮点数值表示。

由于浮点型数值需要的内存空间是保存整数值的两倍,因此,JS 会不失时机地将浮点数值转换成整数值,若小数点后没有跟任何数字或者浮点值本身表示的就是一个整数,这个数值会作为整数值来保存。

console.log(1.0,1.0===1);  // 1 true
console.log(1.,1.===1);  // 1 true

当一个数字直接出现在 JS 中时,称为数值直接量/字面量;使用 new 操作符用做构造函数时,称为 Number 对象。


[ 整数 ] JS 整数表示共有四种字面量格式:十进制、二进制、八进制、十六进制。

但,在进行算术计算时,所有以二进制、八进制和十六进制表示的数值最终都将被转换成十进制数值。

  • 八进制字面值的第一位必须是 0,然后是八进制数字序列(0-7)。如果字面值中的数值超出了范围,那么前导 0 将被忽略,后面的数值被当作十进制数解析。由于某些 JS 的实现不支持八进制字面量,且八进制字面量在严格模式下是无效的,会导致 JS 抛出错误。所以,尽量不使用八进制字面量。
  • 十六进制字面值的前两位必须是0x,后跟十六进制数字序列(0-9,a-f),字母可大写可小写。如果十六进制中字面值中的数值超出范围,如出现 g、h 等会报错。
  •  二进制字面值的前两位必须是 0b,如果出现除 0、1 以外的数字会报错。
var num2 = 0b101;
console.log(num2);  // 5

var num2 = 0b2;
console.log(num2);  // 报错

var num8 = 012;
console.log(num8);  // 10

var num8 = 09;
console.log(num8);  // 9

var num16 = 0x11;
console.log(num16);  // 17

var num16 = 0xg;
console.log(num16);  // 报错

[ 浮点数 ] 数值中必须包含一个小数点,且小数点后面必须至少有一位数字。

// 与整数支持多进制不同,一般地,浮点数只可用十进制表示。

var num1 = 011.1;  // 报错
var num2 = 0x11.1;  // 报错
var num3 = 011e1;  // 报错
var num4 = 0x11e1;  // 出错,会被识别成整数,结果为4577

// 虽然小数点前面可以没有整数,但不推荐。

var num1 = 1.1;
var num2 = 1.;
var num3 = .1; 
console.log(num1,num2,num3);  // 1.1,1,0.1

// 由于JavaScript采用IEEE754格式表示数字,浮点数不是精确值,所以涉及浮点数的比较和运算时要特别小心。

console.log(0.1 + 0.2 === 0.3);  // false
console.log(0.3 / 0.1);  // 2.9999999999999996
console.log((0.3 - 0.2) === (0.2 - 0.1));  // false

[ 科学计数法 ] 对于极大或者极小的数,可以用科学计数法 e 来表示的浮点数值来表示。科学计数法允许字母 e 或 E 的后面,跟着一个整数,表示这个数值的指数部分。以下两种情况,JavaScript 会自动将数值转为科学计数法表示:

  • 小于 1 且小数点后面带有 6 个 0 以上的浮点数值
0.0000003 // 3e-7
0.000003 // 0.000003
  • 整数位数字多于 21 位
1234567890123456789012    // 1.2345678901234568e+21
1234567890123456789012.1   // 1.2345678901234568e+21
123456789012345678901     // 123456789012345680000

[ 特殊值 ] 最值、无穷大、非数字、正负零

[1] 最值

Number.MAX_VALUE 代表 JavaScript 最大值,Number.MIN_VALUE 代表 JavaScript 最小正值。

console.log(Number.MIN_VALUE,Number.MAX_VALUE)  // 5e-324,1.7976931348623157e+308
 
// 安全整数
Number.MAX_SAFE_INTEGER表示最大整数(2的53次幂-1),Number.MIN_SAFE_INTEGER表示最小整数-(2的53次幂-1)。
 
// 9007199254740991 true
console.log(Number.MAX_SAFE_INTEGER,Number.MAX_SAFE_INTEGER===Math.pow(2, 53)-1)
// -9007199254740991 true
console.log(Number.MIN_SAFE_INTEGER,Number.MIN_SAFE_INTEGER===-(Math.pow(2, 53)-1))

[2] 无穷大 Infinity

Infinity 是一个全局属性,用来存放表示无穷大的特殊数值。实际上,Number.POSITIVE_INFINITY 对应的是Infinity,代表正无穷;而 Number.NEGATIVE_INFINITY 对应的是 -Infinity,代表负无穷。

consolec .log(Number.POSITIVE_INFINITY,Number.NEGATIVE_INFINITY);//Infinity -Infinity
  • 用 for/in 循环不可枚举 Infinity 属性,用 delete 操作符也无法删除它。
  • Infinity 有正负之分。
Math.pow(2,Math.pow(2,100));  //Infinity
1/0;  //Infinity
-0/0;  //-Infinity
Infinity === -Infinity;  //false
  • Infinity 参与的运算结果只能是其本身、0 或 NaN。
2 * Infinity;    // Infinity
2 - Infinity;    // -Infinity
2 + Infinity;    // Infinity
2 / Infinity;    // 0
Infinity / 2;    // Infinity

Infinity * Infinity;    // Infinity
Infinity - Infinity;    // NaN
Infinity + Infinity;    // Infinity
Infinity / Infinity;    // NaN
  • 可以通过 isFinite() 来确定一个数值是不是有穷的,包含着隐式类型转换 Number()。如果是 +-Infinity 或 NaN时,返回 false,否则为 true。
console.log(isFinite(Infinity))   // false
console.log(isFinite(NaN))   // false
console.log(isFinite(Number.MAX_VALUE))   // true
console.log(isFinite(true))   // true

[3] 非数字 NaN                                                          //  not a number

NaN 表示非数字,NaN 与任何值都不相等,包括 NaN 本身,且任何涉及 NaN 的操作都会返回 NaN。

5 - 'x';     // NaN
Math.acos(2);     // NaN
0 / 0;     // NaN

NaN == NaN;    // false
NaN == Infinity;    // false

[NaN].indexOf(NaN);    // -1
Boolean(NaN);     // false
  • isNaN() 来判断这个数字是不是 NaN,包含着隐式类型转换 Number();
console.log(isNaN(Infinity));//false
console.log(isNaN(0));//false
console.log(isNaN(NaN));//true
console.log(isNaN('Hello'));//true
  • 判断 NaN 更可靠的方法是,利用 NaN 是 JavaScript 之中唯一不等于自身的值这个特点,进行判断。
function myIsNaN(value) {
  return value !== value;
}

[4] 正负零

在 JS 内部,实际上存在 2 个 0 :一个是 +0,一个是 -0。它们是等价的。

-0 === +0;    // true
0 === -0;    // true
0 === +0;    // true

一般地,+0 和 -0 都会被当做 0 来看待,但是 +0 或 -0 当作分母,返回的值是不相等的。

console.log(1/+0);    // Infinity
console.log(1/-0);    // -Infinity
console.log((1/+0) === (1/-0));    // false

实例方法

关于 Number() 对象的实例方法总共有 6 个,分为两类:


[1] 对象通用方法:toString()、toLocalString()、valueOf()

  • valueOf() 方法返回对象的数字字面量
  • toString() 方法将数字转换为字符串
  • toLocalString() 方法将数字转换为本地惯例格式化数字的字符串

console.log(typeof 1.1.valueOf(),1.1.valueOf());  // number 1.1
console.log(typeof 1.1.toString(),1.1.toString());  // String '1.1'
console.log(typeof 1.1.toLocaleString(),1.1.toLocaleString());  // String '1.1'

[注意]如果数字不加括号,点会被javascript引擎解释成小数点,从而报错

console.log(typeof 1.valueOf(),1.valueOf());  // 报错
console.log(typeof 1.toString(),1.toString());  // 报错
console.log(typeof 1.toLocaleString(),1.toLocaleString());  // 报错

console.log(typeof (1).valueOf(),(1).valueOf());  // number 1
console.log(typeof (1).toString(),(1).toString());  // String '1'
console.log(typeof (1).toLocaleString(),(1).toLocaleString());  // String '1'

除了为数字加上括号,还可以在数字后面加两个点,javascript会把第一个点理解成小数点,把第二个点理解成调用对象属性,从而得到正确结果。

console.log(10..toString());  // "10"
console.log(10 .toString());  // "10"
console.log(10.0.toString());  // "10"

toString()方法可以接受一个参数,该参数应当是2到36之间的整数,表示输出的进制。如果该参数不存在,或者为undefined,默认将数值先转为十进制,再输出字符串。

var num = 10;
console.log(num.toString());  // '10'
console.log(num.toString(2));  // '1010'
console.log(num.toString(8));  // '12'
console.log(num.toString(10));  // '10'
console.log(num.toString(16));  // 'a'    
console.log(num.toString(undefined));  // '10'

如果参数超出2-36的范围,或者为其他值时,报错

console.log((10).toString(0));  // 报错
console.log((10).toString(null));  // 报错

[2] 改变数值显示形式并转换为字符串的方法:toFixed()、toExponential()、toPrecision()

  • toFixed():按照指定的小数位返回数值四舍五入后的字符串表示( 常用于处理货币值 )。
// toFixed()里的参数只接受0-20,若不传参或参数为undefined,则相当于参数是0。

var num = 10.456;
console.log(num.toFixed(2));  // '10.46'
console.log(num.toFixed());  // '10'
console.log(num.toFixed(0));  // '10'
console.log(num.toFixed(undefined));  // '10'
console.log(num.toFixed(-1));  // 报错
  • toExponential():返回数值四舍五入后的指数表示法( e 表示法 )的字符串表示,参数表示转换后的小数位数。
// toExponential()方法里的参数只接受0-20,
// 但与toFxied()不同的是,若不传参或参数为undefined,则保留尽可能多的有效数字;若参数是0表示没有小数部分。

var num = 10.456;
console.log(num.toExponential(2));  // '1.05e+1'
console.log(num.toExponential());  // '1.0456e+1'
console.log(num.toExponential(0));  // '1e+1'
console.log(num.toExponential(undefined));  // '1.0456e+1'
console.log(num.toExponential(-1));  // 报错
  • toPrecision():接收一个参数,即表示数值所有数字的位数(不包括指数部分),自动调用 toFixed() 或 toExponential()
// toPrecision()里的参数只接受1-21,若不传参或参数为undefined则相当于调用toString()方法。

var num = 10.1;
console.log(num.toPrecision(3));  // '10.1'
console.log(num.toPrecision(2));  // '10'       
console.log(num.toPrecision(1));  // '1e+1'
console.log(num.toPrecision());  // '10.1'
console.log(num.toPrecision(undefined));  // '10.1'
console.log(num.toPrecision(0));  // 报错

[ 注意 ] toFixed()、toExponential()、toPrecision() 在小数位用于四舍五入时都不太可靠,跟浮点数不是精确储存有关。

console.log((12.25).toPrecision(3));  // "12.3"
console.log((12.25).toFixed(1));  // "12.3"
console.log((12.25).toExponential(2));  // "1.23e+1"
console.log((12.35).toPrecision(3));  // "12.3"
console.log((12.35).toFixed(1));  // "12.3"
console.log((12.35).toExponential(2));  // "1.23e+1"