ES6 数值的扩展

153 阅读6分钟
  1. ES6分别用前缀0b(或0B)和0o(或0O)表示二进制和八进制数值。
0b111110111 // 503
0o767 // 503

如果要将0b0o前缀的字符串数值转为十进制,要使用Number方法。

Number('0b111') // 7
Number('0o10') // 8
  1. ES2021中,较长的数值允许使用_作为分隔符,该数值分隔符不指定间隔的位数;小数和科学计数法也能使用数值分隔符。
1_000_000_000_000 === 10 ** 12 // true

12_300 === 123_00 // true

0.000_001

1e10_000

数值分隔符的注意点:

  • 不能放在数值的最前面或最后面
  • 不能两个或两个以上的分隔符连在一起
  • 小数点前后不能有分隔符
  • 科学计数法里表示指数的eE前后不能有分隔符

下面三个函数不支持数值分隔符。

Number('123_456') // NaN
parseInt('123_456') // 123
parseFloat('123_456') // 123
  1. Number.isFinite()用来检查一个数值是否为有限的。如果参数类型不是数值,一律返回false
Number.isFinite(14) // true
Number.isFinite(NaN) // false
Number.isFinite(-Infinity) // false
Number.isFinite('foo') // false
Number.isFinite(true) // false

Number.isNaN()用来检查一个值是否为NaN。如果参数类型不是NaN,一律返回false

Number.isNaN(NaN) // true
Number.isNaN(15) // false
  1. Number.parseInt()Number.parseFloat()是移植到Number对象上的parseInt()parseFloat()
Number.parseInt === parseInt // true
Number.parseFloat === parseFloat // true
  1. Number.isInteger()用来判断一个数值是否为整数。如果参数不是数值,则返回false。在JavaScript内部,整数和浮点数采用的是同样的储存方法,所以25和25.0被视为同一个值。
Number.isInteger(25.1) // false
Number.isInteger(25) // true
Number.isInteger(25.0) // true

由于JavaScript的数值存储为64位双精度格式,数值精度最多可以达到53个二进制位。如果数值精度超过这个限度,第54位及后面的位就会被舍弃,在这种情况下,Number.isInteger()可能会误判。

Number.isInteger(3.000000000000000002) / true

如果一个数值的绝对值小于5E-324,会被自动转为0,这时Number.isInteger()也会误判。

Number.isInteger(5E-324) // false
Number.isInteger(5E-325) // true

6.Number.EPSILON表示1与大于1的最小浮点数之间的差。对于64位浮点数来说,大于1的最小浮点数相当于二进制的1.00..001(小数点后有连续51个零),这个值减去1后就等于2的-52次方。

Number.EPSILON === Math.pow(2,-52) // true

Number.EPSILON实质是一个可以接受的最小误差范围。比如误差范围设为2的-50次方(即Number.EPSILON * Math.pow(2,2)),如果两个浮点数的差小于这个误差范围,我们就认为这两个浮点数相等。

0.1 + 0.2 === 0.3 // false
0.1 + 0.2 - 0.3 // 5.551115123125783e-17
5.551115123125783e-17 < Number.EPSILON * Math.pow(2,2) // true
  1. 常量Number.MAX_SAFE_INTEGERNumber.MIN_SAFE_INTEGER表示安全整数范围的上下限。
Number.MAX_SAFE_INTEGER // 9007199254740991
Number.MIN_SAFE_INTEGER // -9007199254740991

Number.isSafeInteger()用来判断一个整数是否落在安全整数范围之内。

Number.isSafeInteger('a') // false
Number.isSafeInteger('9007199254740990') // true
Number.isSafeInteger('1.2') // false

Number.isSafeInteger()相当于以下函数:

Number.isSafeInteger = function (n) {
    return (typeof n === 'number' && Math.round(n) === n && Number.Min_SAFE_INTEGER <= n && Number.MAX_SAFE_INTEGER >= n)
}

使用这个函数验证运算结果是否落在安全整数的范围内,同时也要验证参与运算的每个值。

Number.isSafeInteger(9007199254740993) // false
Number.isSafeInteger(990) // true
Number.isSafeInteger(9007199254740993-990) // true
9007199254740993-990 // 返回9007199254740002,实际为9007199254740003

Math对象的扩展

Math.trunc()

Math.trunc去除一个数的小数部分,返回整数部分。

Math.trunc(4.1) // 4

对于非数值,Math.trunc使用Number方法先将其转化为数值。

Math.trunc('123.456') // 123
Math.trunc(null) // 0
Math.trunc(true) // 1

对于空值和无法截取整数的值,返回NaN

Math.trunc('foo') // NaN
Math.trunc() // NaN

Marh.sign()

Math.sign用于判断一个数是正数、负数、还是零。对于非数值,会先将其转换为数值。

Math.sign(2) // +1 参数为正数 返回+1
Math.sign(-2) // -1 参数为负数 返回=1
Math.sign(0) // 0 参数为0 返回0
Math.sign(-0) // -0 参数为-0 返回-0
Math.sign(NaN) // NaN 其他值返回NaN

Math.cbrt()

Math.cbrt用于计算一个数的立方根。对于非数值,会先将其转换为数值。

Math.cbrt(-1) // -1
Math.cbrt(2) // 1.2599210498948732

Math.clz32()

Math.clz32()将参数转为32位无符号整数的形式,然后返回这个32位值里面有多少个前导0.

// 10的二进制形式是0b1010,1010只占了4位,所以32位之中有28个前导0
Math.clz(10) // 28

对于小数,Math.clz32()只考虑整数部分。

Math.clz32(3.2) // 30

对于空值或其他类型的值,Math.clz32()先将其转为数值再进行计算。

Math.imul()

Math.imul方法返回两个数以32位带符号整数形式相乘的结果,返回的也是一个32位的带符号整数。

Math.imul(2, 4) // 8

如果只考虑最后32位,大多数情况下,Math.imul(a, b)a * b的结果是相同的,即该方法等同于(a * b)|0

Math.fround()

Math.fround返回一个数的32位单精度浮点数形式。对于32位单精度格式来说,数值精度是24个二进制位,所以对于-224 至224之间的整数(不含两个端点),返回结果与参数本身一致。

Math.fround(2 ** 24 - 1) //16777215

当参数绝对值大于224,返回的结果会丢失精度。

Math.fround(2 ** 24) //16777216
Math.fround(2 ** 24 + 1) //16777216

Math.hypot()

Math.hypot返回所有参数的平方和(即a2+b2)的平方根。

Math.hypot(3, 4) // 5
Math.hypot() // 0
Math.hypot(3, '4') // 5
Math.hypot(NaN) // NaN
Math.hypot(-3) // 3

如果参数不是数值,Math.hypot会先将其转为数值。只要有一个参数无法转为数值,就会返回NaN。

对数方法

  1. Math.expm1()返回ex-1,即Math.exp(x)-1
Math.expm1(0) // 0
Math.expm1(1) // 1.718281828459045

对于没有部署这个方法的环境,可以用以下代码模拟。

Math.expm1 = Math.expm1 || function(x) {
    return Math.exp(x) - 1;
}
  1. Math.log1p(x)返回1 + x的自然对数,即Math.log(1 + x)。如果x小于-1,返回NaN
Math.log1p(0) // 0
  1. Math.log10(x)返回以10为底的x的对数。如果x小于0,则返回NaN。
Math.log10(1) // 0
Math.log10(10) // 1
  1. Math.log2(x)返回以2为底的x的对数。如果x小于0,则返回NaN。
Math.log2(2) // 1

BigInt数据类型

JavaScript所有数字都保存成64位浮点数,这给数值的表示带来了两大限制。一是数值的精度只能到53个二进制位(相当于16个十进制位),大于这个范围的整数无法被JavaS精确表示。二是JavaScript无法表示大于或等于2的1024次方的数值,会返回Infinity
BigInt(大整数)是ECMAScript的第八种数据类型。它只用来表示整数,没有位数的限制,任何位数的整数都可以精确表示。BigInt类型的数据必须添加后缀n

const a = 2172141653n;
const b = 15346349309n;
a * b // 33334444555566667777n

const x = 2172141653;
const y = 15346349309;
x * y // 33334444555566670000

BigInt函数

BigInt函数可以将其他类型的值转为BigInt。当没有参数或者参数不能正常转为数值时都会报错。

BigInt(1234) // 1234n
BigInt(false) // 0n
BigInt('123') // 123n

// 参数为小数时也会报错
BigInt(1.5) // RangeError

取反运算符(!)可以将BigInt转为布尔值。

!0n // true