数值的扩展

2024/1/31 JavaScript

# 二进制和八进制表示法

​ ES6提供了二进制和八进制数值的新的写法,分别用前缀0b(或0B)和0o(或0O)表示。如果要将它们转为十进制,要使用Number()方法。

Number('0b111')  // 7
Number('0o10')  // 8
1
2

# 数值分隔符

​ ES2021允许JavaScript的数值使用下划线(_)作为分隔符。这个数值分隔符没有指定间隔的位数,可以每三位添加一个分隔符,也可以每一位、每两位、每四位添加一个。小数和科学计数法也可以使用数值分隔符。数值分隔符只是一种书写便利,对JavaScript内部数值的存储和输出并没有影响。

​ 数值分隔符有几个使用注意点:①不能放在数值的最前面(leading)或最后面(trailing)。②不能两个或两个以上的分隔符连在一起。③小数点的前后不能有分隔符。④科学计数法里面,表示指数的e或E前后不能有分隔符。

​ 除了十进制,其他进制的数值也可以使用分隔符。数值分隔符可以按字节顺序分隔数值,这在操作二进制位时,非常有用。注意,分隔符不能紧跟着进制的前缀0b、0B、0o、0O、0x、0X。

​ Number()、parseInt()、parseFloat()这三个将字符串转成数值的函数,不支持数值分隔符。主要原因是语言的设计者认为,数值分隔符主要是为了编码时书写数值的方便,而不是为了处理外部输入的数据。

12345_00 === 1_234_500 // true
1e10_000 // 科学计数法
0.000_001 // 小数
0b1010_0001_1000_0101 // 二进制
1
2
3
4

# Number.isFinite(), Number.isNaN()

  • Number.isFinite()用来检查一个数值是否为有限的(finite),即不是Infinity。如果参数类型不是数值,一律返回false。
  • Number.isNaN()用来检查一个值是否为NaN。如果参数类型不是NaN,一律返回false,只有对于NaN才返回true,。
Number.isFinite(25) // true
Number.isFinite("25") // false
Number.isNaN(NaN) // true
Number.isNaN("NaN") // false
1
2
3
4

# Number.parseInt(), Number.parseFloat()

​ ES6将全局方法parseInt()和parseFloat(),移植到Number对象上面,行为完全保持不变。这样做的目的,是逐步减少全局性方法,使得语言逐步模块化。

Number.parseInt('12.34') // 12
Number.parseFloat('123.45#') // 123.45
Number.parseInt === parseInt // true
Number.parseFloat === parseFloat // true
1
2
3
4

# Number.isInteger()

​ Number.isInteger()用来判断一个数值是否为整数,如果参数不是数值,返回false。JavaScript内部,整数和浮点数采用的是同样的储存方法,所以 25 和 25.0 被视为同一个值。如果对数据精度的要求较高,不建议使用Number.isInteger()判断一个数值是否为整数。

//由于JS数值存储为64位双精度格式,数值精度最多可以达到53个二进制位(1个隐藏位与52个有效位)。超过这个限度,第54位及后面的位就会被丢弃,这时可能会误判。
Number.isInteger(3.0000000000000002) // true  精度达到了小数点后16个十进制位,转成二进制位超过了53个二进制位,导致最后的那个2被丢弃了。
Number.isInteger(5E-324) // false
//数值的绝对值<Number.MIN_VALUE(5E-324),即<JS能分辨的最小值,会被自动转为 0, 这时也会误判。
Number.isInteger(5E-325) // true   5E-325由于值太小,会被自动转为0,因此返回true
1
2
3
4
5

# Number.EPSILON

​ ES6在Number对象上面新增一个极小的常量Number.EPSILON,它表示1与大于1 的最小浮点数之间的差。实际上是JS 能够表示的最小精度,误差若小于这个值,就可以认为已经没有意义了,即不存在误差了。引入的目的在于为浮点数计算,实质是一个可以接受的最小误差范围。

0.1 + 0.2  // 0.30000000000000004
0.1 + 0.2 - 0.3  // 5.551115123125783e-17
5.551115123125783e-17.toFixed(20)  // '0.00000000000000005551'
//Number.EPSILON可以用来设置能够接受的误差范围,如果两个浮点数的差小于这个值,就认为这两个浮点数相等。
function withinErrorMargin (left, right) {
  return Math.abs(left - right) < Number.EPSILON * Math.pow(2, 2);
} // 部署一个误差检查函数
0.1 + 0.2 === 0.3 // false
withinErrorMargin(0.1 + 0.2, 0.3) // true
1.1 + 1.3 === 2.4 // false
withinErrorMargin(1.1 + 1.3, 2.4) // true 
1
2
3
4
5
6
7
8
9
10
11

# 安全整数和 Number.isSafeInteger()

​ JS能准确表示的整数范围在-2^53到2^53之间(不含两个端点),超过这个范围,无法精确表示这个值。ES6引入Number.MAX_SAFE_INTEGER和Number.MIN_SAFE_INTEGER这两个常量,用来表示这个范围的上下限。JavaScript 能够精确表示的极限是-2^53+1到2^53-1。

Math.pow(2, 53) //9007199254740992
Math.pow(2, 53) === Math.pow(2, 53) + 1 // true 超出2^53之后,一个数就不精确了
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
1
2
3
4
5
6

​ Number.isSafeInteger()则是用来判断一个**整数******是否落在这个范围之内。

Number.isSafeInteger(-Infinity) // false
Number.isSafeInteger(1.2) // false。1.2不是一个整数,而是一个浮点数,返回false
Number.isSafeInteger(Number.MAX_SAFE_INTEGER) // true
1
2
3

# Math 对象的扩展

​ 在Math对象上新增了17个与数学相关的方法。所有方法都是静态的,只能在Math对象上调用。

# 常见方法

  • Math.trunc(x):用于去除一个数的小数部分,返回整数部分。对于非数值,Math.trunc内部使用Number方法将其先转为数值。对于空值和无法截取整数的值,返回NaN。
Math.trunc(-4.9) // -4
Math.trunc('123.456') // 123
Math.trunc('foo'); // NaN
1
2
3
  • Math.sign(x):用来判断一个数到底是正数、负数、还是零。它会返回五种值:①参数为正数,返回+1;②参数为负数,返回-1;③参数为 0,返回0;④参数为-0,返回-0;⑤其他值,返回NaN。对于非数值,会先将其转换为数值。对于那些无法转为数值的值,会返回NaN。
Math.sign(0) // +0
Math.sign(-0) // -0
Math.sign('foo')  // NaN
1
2
3
  • Math.cbrt():用于计算一个数的立方根。对于非数值,Math.cbrt()方法内部也是先使用Number()方法将其转为数值。
Math.cbrt('8') // 2
Math.cbrt('hello') // NaN
1
2
  • Math.clz32():将参数转为32位无符号整数的形式,然后返回这个32位值里面有多少个前导0。
Math.clz32(0) // 32
Math.clz32(1000) // 22
//左移运算符(<<)与Math.clz32方法直接相关
Math.clz32(1 << 2) // 29
//对于小数,Math.clz32方法只考虑整数部分
Math.clz32(3.9) // 30
//对于空值或其他类型的值,Math.clz32方法会将它们先转为数值,然后再计算
Math.clz32(Infinity) // 32
1
2
3
4
5
6
7
8
  • Math.imul():返回两个数以32位带符号整数形式相乘的结果,返回一个32位的带符号整数。对于那些很大的数的乘法,低位数值往往都是不精确的,Math.imul方法可以返回正确的低位数值。
(0x7fffffff * 0x7fffffff)|0 // 0
Math.imul(0x7fffffff, 0x7fffffff) // 1
1
2
  • Math.fround():返回一个数的32位单精度浮点数形式。如果小数的精度超过24个二进制位,返回值就会不同于原值,否则返回值不变(即与64位双精度值一致)。对于 NaN 和 Infinity,此方法返回原值。对于其它类型的非数值,Math.fround 方法会先将其转为数值,再返回单精度浮点数。
Math.fround(1.125) // 1.125 未丢失有效精度
Math.fround(0.3)   // 0.30000001192092896 丢失精度
Math.fround({})    // NaN
1
2
3
  • Math.hypot():返回所有参数的平方和的平方根。如果参数不是数值,Math.hypot方法会将其转为数值。只要有一个参数无法转为数值,就会返回 NaN。
Math.hypot(3, 4);        // 5
1

# 对数方法

  • Math.expm1(x):返回 ex - 1,即Math.exp(x) - 1。
  • Math.log1p(x):返回1 + x的自然对数,即Math.log(1 + x)。如果x小于-1,返回NaN。
  • Math.log10(x):返回以 10 为底的x的对数。如果x小于 0,则返回 NaN。
  • Math.log2(x):返回以 2 为底的x的对数。如果x小于 0,则返回 NaN。

# 双曲函数方法

  • Math.sinh(x) :返回x的双曲正弦(hyperbolic sine)
  • Math.cosh(x) :返回x的双曲余弦(hyperbolic cosine)
  • Math.tanh(x) :返回x的双曲正切(hyperbolic tangent)
  • Math.asinh(x) :返回x的反双曲正弦(inverse hyperbolic sine)
  • Math.acosh(x) :返回x的反双曲余弦(inverse hyperbolic cosine)
  • Math.atanh(x) :返回x的反双曲正切(inverse hyperbolic tangent)

# 指数运算符

​ ES2016新增了指数运算符()。 这个运算符是右结合,而不是常见的左结合。多个指数运算符连用时,是从最右边开始计算的。指数运算符可以与等号结合,形成一个新的赋值运算符(=)。

2 ** 3 ** 2 // 相当于 2 ** (3 ** 2)
// 512 首先计算的是第二个指数运算符,而不是第一个
let a = 1.5;
a **= 2; // 等同于 a = a * a;
let b = 4;
b **= 3; // 等同于 b = b * b * b;
1
2
3
4
5
6

# BigInt 数据类型

​ BigInt只用来表示整数,没有位数的限制,任何位数的整数都可以精确表示。为了与Number类型区别,BigInt 类型的数据必须添加后缀n。

0b1101n // 二进制 可以使用各种进制表示,都要加上后缀n。
42n === 42 // false BigInt 与普通整数是两种值,它们之间并不相等。
typeof 123n // 'bigint' typeof运算符对于 BigInt 类型的数据返回bigint。
-42n // 正确 BigInt 可以使用负号(-),但是不能使用正号(+),因为会与 asm.js 冲突。
+42n // 报错
1
2
3
4
5

​ 可以用Boolean()、Number()和String()这三个方法,将BigInt转为布尔值、数值和字符串类型。

​ 数学运算方面,BigInt 类型的+、-、*和**这四个二元运算符,与Number类型的行为一致。除法运算/会舍去小数部分,返回一个整数。

​ BigInt 对应的布尔值,与 Number 类型一致,即0n会转为false,其他值转为true。

​ 比较运算符(比如>)和相等运算符(==)允许 BigInt 与其他类型的值混合计算,因为这样做不会损失精度。

​ BigInt 与字符串混合运算时,会先转为字符串,再进行运算。

上次更新: 2024/4/13 08:06:14