ECMA Script 6_数值的扩展
1. 二进制 和 八进制 新的表示法
前缀 0b
(或0B
) 表示 二进制
前缀 0o
(或 0O
)表示 八进制
-
console.log(0b111110111 === 503); // true console.log(0o767 === 503); // true
- 如果要将
0b
和0o
前缀的字符串数值 转为十进制,要使用Number()
方法
2. Number.isFinite()
检查一个数值是否为有限的(finite),即 不是 Infinity 返回 true
只对数值有效
如果参数类型不是数值,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
3. Number.isNaN()
检查一个值是否为 NaN
只对数值有效
-
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
4. Number.parseInt()
和 Number.parseFloat()
将 全局方法 移植到对象 上面,行为完全保持不变
是为了 逐步减少全局性方法,使得语言逐步模块化
-
Number.parseInt === parseInt // true Number.parseFloat === parseFloat // true
5. Number.isInteger()
判断一个数值是否为整数
- 整数 和 浮点数 采用的是同样的储存方法,所以 25 和 25.0 被视为同一个值
-
Number.isInteger(25); // true Number.isInteger(25.0); // true
- JavaScript 采用 IEEE 754 标准,数值存储为64位双精度格式,数值精度最多可以达到 53 个二进制位(1 个隐藏位与 52 个有效位)。
- 如果数值的精度超过这个限度,第54位及后面的位就会被丢弃,这种情况下,Number.isInteger可能会误判。
-
Number.isInteger(3.0000000000000002); // true
所以,如果对数据精度的要求较高,不建议使用 Number.isInteger() 判断一个数值是否为整数
6. Number.EPSILON
ES6 在 Number 对象上面,新增 一个极小的常量 Number.EPSILON ,即 JavaScript 能够表示的最小精度。
误差如果小于这个值,就可以认为已经没有意义了,即不存在误差了
根据规格,它表示 1 与大于 1 的最小浮点数之间的差
- 对于 64 位浮点数来说,大于 1 的最小浮点数相当于二进制的1.00..001,小数点后面有连续 51 个零。
- 这个值减去 1 之后,就等于 2 的 -52 次方
- 用来设置 “能够接受的误差范围”
比如,误差范围设为 2 的-50 次方(即Number.EPSILON * Math.pow(2, 2)),
即如果两个浮点数的差小于这个值,我们就认为这两个浮点数相等
-
5.551115123125783e-17 < Number.EPSILON * Math.pow(2, 2); // true
- 一个可以接受的最小误差范围
-
// 误差范围设为 2 的 -50 次方
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
7. 安全整数 和 Number.isSafeInteger()
JavaScript 能够准确表示的整数范围在-2^53
到2^53
之间(不含两个端点),超过这个范围,无法精确表示这个值
- Number.isSafeInteger()
判断一个整数是否落在 [-2^53,
2^53]
范围之内
-
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 - 验证 整个运算 是否可靠
-
function trusty (left, right, result) { if ( Number.isSafeInteger(left) && Number.isSafeInteger(right) && Number.isSafeInteger(result) ){ return result; }; throw new RangeError('Operation cannot be trusted!'); }; trusty(9007199254740993, 990, 9007199254740993 - 990); // RangeError: Operation cannot be trusted! trusty(1, 2, 3); // 3
Math 对象的扩展
Math.trunc()
去除一个数的小数部分,返回整数部分
对于非数值,Math.trunc() 内部使用 Number() 将其先转为数值
-
Math.trunc(4.1); // 4 Math.trunc(4.9); // 4 Math.trunc(-4.1); // -4 Math.trunc(-4.9); // -4 Math.trunc(-0.1234); // -0 Math.trunc('123.456'); // 123 Math.trunc(true); //1 Math.trunc(false); // 0 Math.trunc(null); // 0
Math.sign()
判断一个数到底是 正数、负数、还是 零
对于非数值,会先将其转换为数值
-
参数为正数, 返回+1; 参数为负数, 返回-1; 参数为 0, 返回0; 参数为-0, 返回-0; 其他值, 返回NaN
Math.sign(-5); // -1 Math.sign(5); // +1 Math.sign(0); // +0 Math.sign(-0); // -0 Math.sign(NaN); // NaN
Math.cbrt
用于计算一个数的立方
于非数值,Math.cbrt() 方法内部也是先使用 Number() 将其转为数值
-
Math.cbrt('8'); // 2
Math.clz32()
返回一个数的 32 位无符号整数形式有多少个前导 0
JavaScript 中,整数使用 32 位二进制形式表示
”count leading zero bits in 32-bit binary representation of a number“(计算一个数的 32 位二进制形式的前导 0 的个数)的缩写
-
Math.clz32(0); // 32 Math.clz32(1); // 31 Math.clz32(1000); // 22 Math.clz32(0b01000000000000000000000000000000); // 1 Math.clz32(0b00100000000000000000000000000000); // 2
- 左移运算符(<<)与 Math.clz32() 直接相关
-
Math.clz32(0); // 32 Math.clz32(1); // 31 Math.clz32(1 << 1); // 30 Math.clz32(1 << 2); // 29 Math.clz32(1 << 29); // 2
- 对于小数,
Math.clz32
() 只考虑整数部分 -
Math.clz32(3.2); // 30 Math.clz32(3.9); // 30
- 对于空值或其他类型的值,Math.clz32() 会将它们先转为数值,然后再计算
-
Math.clz32(); // 32 Math.clz32(NaN); // 32 Math.clz32(Infinity); // 32 Math.clz32(null); // 32 Math.clz32('foo'); // 32 Math.clz32([]); // 32 Math.clz32({}); // 32 Math.clz32(true); // 31
Math.imul()
返回两个数以 32 位带符号整数形式相乘的结果,
返回的也是一个 32 位的带符号整数
-
Math.imul(2, 4); // 8 Math.imul(-1, 8); // -8 Math.imul(-2, -2); // 4
Math.fround()
返回一个数的 32 位单精度浮点数形式
主要作用,是将64位双精度浮点数转为32位单精度浮点数。
如果小数的精度超过 24 个二进制位,返回值就会不同于原值,
否则返回值不变(即与64位双精度值一致)
- 对于32位单精度格式来说,数值精度是24个二进制位(1 位隐藏位与 23 位有效位),所以对于 -224 至 224 之间的整数(不含两个端点),返回结果与参数本身一致
-
Math.fround(0); // 0 Math.fround(1); // 1 Math.fround(2 ** 24 - 1); // 16777215
- 如果参数的绝对值大于 2的24次方,返回的结果便开始丢失精度
-
Math.fround(2 ** 24); // 16777216 Math.fround(2 ** 24 + 1); // 16777216
Math.hypot()
返回 所有参数的平方和 的平方根
-
Math.hypot(3, 4); // 5 Math.hypot(3, 4, 5); // 7.0710678118654755 Math.hypot(); // 0 Math.hypot(NaN); // NaN Math.hypot(3, 4, 'foo'); // NaN Math.hypot(3, 4, '5'); // 7.0710678118654755 Math.hypot(-3); // 3
新增的 4 个 对数方法
Math.expm1(x)
返回 e 的 x 次方 - 1,即 Math.exp(x) - 1
Math.log1p()
返回 1 + x
的自然对数,即 Math.log(1 + x)
如果 x
小于-1,返回 NaN
Math.log10()
返回以 10 为底的 x 的对数。
如果 x 小于 0,则返回 NaN
-
Math.log10(2); // 0.3010299956639812 Math.log10(1); // 0 Math.log10(0); // -Infinity Math.log10(-2); // NaN Math.log10(100000); // 5
Math.log2()
333
-
Math.log2(3); // 1.584962500721156 Math.log2(2); // 1 Math.log2(1); // 0 Math.log2(0); // -Infinity Math.log2(-2); // NaN Math.log2(1024); // 10 Math.log2(1 << 29); // 29
双曲函数方法
-
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)
指数运算符
ES6 新增了一个指数运算符(**)
-
2 ** 2 // 4 2 ** 3 // 8
- 右结合,而不是常见的左结合。
多个指数运算符连用时,是从最右边开始计算的
-
2 ** 3 ** 2 // 相当于 2 ** (3 ** 2) // 512
- 指数运算符可以与等号结合,形成一个新的赋值运算符(
**=
) -
let a = 1.5; a **= 2; // 等同于 a = a * a; 2.25 let b = 4; b **= 3; // 等同于 b = b * b * b; 64
- 注意: V8 引擎的 指数运算符 与
Math.pow()
的实现不相同,对于特别大的运算结果,两者会有细微的差异 -
Math.pow(99, 99) // 3.697296376497263e+197 99 ** 99 // 3.697296376497268e+197 // 上面代码中,两个运算结果的最后一位有效数字是有差异的。