ES6学习二
数值的扩展
1. 二进制、八进制和十六进制表示法
1.1 不同进制的表示
在js中,10进制
是不需要任何特殊表示方法的,但是2进制
与8进制
和16进制
则需要特殊表示。
在以前前,JS表示16进制
的数字,需要以0x
(或0X
)开头
0x00 === 0 // true
0x0A === 10 // true
0x0F === 15 // true
0x10 === 16 // true
表示8进制
的数字,需要以0
开头
000 === 0 // true
007 === 7 // true
010 === 8 // true
表示2进制
的数字,需要以0b
(或0B
)开头
0b00 === 0 // true
0b01 === 1 // true
0b10 === 2 // true
但是8进制
这种以0
开头的表示方法容易引起歧义,有的浏览器会当作10进制
来解析,所以从 ES5 开始,在严格模式之中,八进制就不再允许使用前缀0表示,ES6进一步明确,要使用前缀0o
(或0O
)表示
0o00 === 0 // true
0o07 === 7 // true
0o10 === 8 // true
1.2 不同进制转换
- 使用
Number
方法可以将不同进制的数值转为十进制的数值
Number(0x10) // 16
Number(0O10) // 8
Number(0b10) // 2
- 使用
toString()
方法转化成任意进制的字符串(得到的结果不带前缀)
0b11111.toString(2) === '1111'
0b11111.toString(8) === '37'
// 默认转为10进制
0b11111.toString() === '31'
0b11111.toString(16) === '1f'
// 非常规进制也可以转换
0b11111.toString(6) === '51'
2. Number对象的方法
2.1 Number.isFinite(), Number.isNaN()
ES6 在Number对象上,新提供了Number.isFinite()和Number.isNaN()两个方法。
它们与传统的全局方法isFinite()
和isNaN()
的区别在于,传统方法先调用Number()
将非数值的值转换为数值,再进行判断,而这两个新方法只对数值有效。
Number.isFinite()
用来检查一个数值是否为有限的(finite),即不是Infinity
。同时,如果参数类型不是数值
,Number.isFinite
一律返回false
。
Number.isFinite(15); // true
Number.isFinite(0.8); // true
Number.isFinite(NaN); // false
Number.isFinite(Infinity); // false
Number.isFinite(-Infinity); // false
Number.isFinite('foo'); // false
Number.isFinite('15'); // false
Number.isFinite(true); // false
Number.isNaN()
用来检查一个值是否为NaN
。同时,如果参数类型不是NaN
,Number.isNaN
一律返回false
。
Number.isNaN(NaN) // true
Number.isNaN(15) // false
Number.isNaN('15') // false
Number.isNaN(true) // false
Number.isNaN(9/NaN) // true
Number.isNaN('true' / 0) // true
Number.isNaN('true' / 'true') // true
2.2 和安全整数和Number.isInteger(),Number.isSafeInteger()
由于 JavaScript 采用 IEEE 754 标准,数值存储为64位双精度格式,数值精度最多可以达到 53 个二进制位(1 个隐藏位与 52 个有效位)。即JavaScript 能够准确表示的整数范围在-2^53
到2^53
之间(不含两个端点),如果数值的精度超过这个限度,第54位及后面的位就会被丢弃。
Math.pow(2, 53) // 9007199254740992
9007199254740992 // 9007199254740992
9007199254740993 // 9007199254740992 (精度丢失)
Math.pow(2, 53) === Math.pow(2, 53) + 1
// true
- ES6 引入了
Number.MAX_SAFE_INTEGER
和Number.MIN_SAFE_INTEGER
这两个常量,用来表示这个范围的上下限。
Number.MAX_SAFE_INTEGER === Math.pow(2, 53) - 1
// true
Number.MAX_SAFE_INTEGER === 9007199254740991
// true
Number.MIN_SAFE_INTEGER === -Number.MAX_SAFE_INTEGER
// true
Number.MIN_SAFE_INTEGER === -9007199254740991
// true
Number.isSafeInteger()
则是用来判断一个整数是否落在安全范围之内。
Number.isSafeInteger('a') // false
Number.isSafeInteger(null) // false
Number.isSafeInteger(NaN) // false
Number.isSafeInteger(Infinity) // false
Number.isSafeInteger(-Infinity) // false
Number.isSafeInteger(3) // true
Number.isSafeInteger(1.2) // false
Number.isSafeInteger(9007199254740990) // true
Number.isSafeInteger(9007199254740992) // false
Number.isSafeInteger(Number.MIN_SAFE_INTEGER - 1) // false
Number.isSafeInteger(Number.MIN_SAFE_INTEGER) // true
Number.isSafeInteger(Number.MAX_SAFE_INTEGER) // true
Number.isSafeInteger(Number.MAX_SAFE_INTEGER + 1) // false
实际使用这个函数时,需要注意。验证运算结果是否落在安全整数的范围内,不要只验证运算结果,而要同时验证参与运算的每个值。
在计算中,如果参与计算的某一个值超出了精度范围,计算机内部,会以9007199254740992
的形式储存,即以9007199254740992
参与实际计算。
Number.isSafeInteger(9007199254740993)
// false
Number.isSafeInteger(990)
// true
Number.isSafeInteger(9007199254740993 - 990)
// true
9007199254740993 - 990
// 返回结果 9007199254740002 = 9007199254740992-990
// 正确答案应该是 9007199254740003 = 9007199254740993 - 990
Number.isInteger()
用来判断一个数值是否为整数。同时,如果参数不是数值
,Number.isInteger
返回false
Number.isInteger(25) // true
Number.isInteger(25.0) // true
Number.isInteger(25.1) // false
// 参数不是数值
Number.isInteger() // false
Number.isInteger(null) // false
Number.isInteger('15') // false
Number.isInteger(true) // false
// 小数的精度达到了小数点后16个十进制位,转成二进制位超过了53个二进制位,导致最后的那个2被丢弃了
Number.isInteger(3.0000000000000002) // true
Number.isInteger(5E-324) // false
// 5E-325小于最小值5E-324,会被自动转为0,因此返回true
Number.isInteger(5E-325) // true
注意
- JavaScript 内部,整数和浮点数采用的是同样的储存方法,所以 25 和 25.0 被视为同一个值。
- 同样受精度影响,超过安全范围的值可能会判断误判。
Number对象没有判断是否为浮点数的方法,因为非数值Number.isInteger
也会被判断为false
,所以并不能单纯用取反Number.isInteger
来判断是否为浮点数
const a = 0.01
const b = '0.01'
Number.isInteger(a) // true
Number.isInteger(b) // true
// 联合Number.isFinite方法一起判断
Number.isFinite(a) && !Number.isInteger(a) // true
Number.isFinite(b) && !Number.isInteger(b) // false
2.3 Number.parseInt(), Number.parseFloat()
ES6 将全局方法parseInt()和parseFloat(),移植到Number对象上面,行为完全保持不变。
这样做的目的,是逐步减少全局性方法,使得语言逐步模块化。
// ES5的写法
parseInt('12.34') // 12
parseFloat('123.45#') // 123.45
// ES6的写法
Number.parseInt('12.34') // 12
Number.parseFloat('123.45#') // 123.45
3. 数值分隔符
欧美语言中,较长的数值允许每三位添加一个分隔符(通常是一个逗号),增加数值的可读性。比如,1000可以写作1,000。
ES2021,允许 JavaScript 的数值使用下划线(_
)作为分隔符。这个数值分隔符没有指定间隔的位数,也就是说,可以每三位添加一个分隔符,也可以每一位、每两位、每四位添加一个。而且整数
和小数
,包括科学计数法
都可以添加
// 整数
123_00 === 12_300 // true
12345_00 === 123_4500 // true
12345_00 === 1_234_500 // true
// 小数
0.000_001
// 科学计数法
1e10_000
// 二进制
0b1010_0001_1000_0101
// 八进制
0o76_543_21_0
// 十六进制
0xA0_B0_C0
数值分隔符有几个使用注意点。
- 不能放在数值的最前面(leading)或最后面(trailing)。
- 不能两个或两个以上的分隔符连在一起。
- 小数点的前后不能有分隔符。
- 科学计数法里面,表示指数的e或E前后不能有分隔符。
- 分隔符不能紧跟着进制的前缀
0b
、0B
、0o
、0O
、0x
、0X
数值分隔符只是一种书写便利,对于 JavaScript 内部数值的存储和输出,并没有影响。同时数值分隔符也只有数值类型支持,如果换成字符串则会被当做普通字符串处理。主要原因是语言的设计者认为,数值分隔符主要是为了编码时书写数值的方便,而不是为了处理外部输入的数据。
Number('123_456') // NaN
Number(123_456) // 123456
parseInt('123_456.01') // 123
parseInt(123_456.01) // 123456
parseFloat('0.000_100') // 0
parseFloat(0.000_100) // 0.0001