本篇博客学习摘自阮一峰老师编写的《ECMAScript 6 入门》,记录下做笔记。
学习阶段,如果哪部分有问题,欢迎指正,共同探讨。@Apach3
1.二进制和八进制表示法
ES6 提供了二进制和八进制数值的新的写法,分别用前缀0b
(或0B
)和0o
(或0O
)表示。
0b111110111 === 503 // true
0o767 === 503 // true
如果要将0b
和0o
前缀的字符串数值转为十进制,要使用Number
方法。
Number('0b111') // 7
Number('0o10') // 8
2.Number.isFinite(), Number.isNaN()
ES6 在Number
对象上,新提供了Number.isFinite()
和Number.isNaN()
两个方法。
Number.isFinite()
用来检查一个数值是否为有限的(finite
)。
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
。
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
它们与传统的全局方法isFinite()
和isNaN()
的区别在于,传统方法先调用Number()
将非数值的值转为数值,再进行判断,而这两个新方法只对数值有效,Number.isFinite()
对于非数值一律返回false
, Number.isNaN()这里写代码片
只有对于NaN
才返回true
,非NaN
一律返回false
。
3.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
4.Number.isInteger()
Number.isInteger()
用来判断一个值是否为整数。需要注意的是,在 JavaScript 内部,整数和浮点数是同样的储存方法,所以3和3.0被视为同一个值。
Number.isInteger(25) // true
Number.isInteger(25.0) // true
Number.isInteger(25.1) // false
Number.isInteger("15") // false
Number.isInteger(true) // false
5.Number.EPSILON
ES6 在Number
对象上面,新增一个极小的常量Number.EPSILON
。根据规格,它表示1与大于1的最小浮点数之间的差。对于64位浮点数来说,大于1的最小浮点数相当于二进制的1.00..001
,小数点后面有连续51个零。这个值减去1之后,就等于2的-52次方。
Number.EPSILON
可以用来设置“能够接受的误差范围”。比如,误差范围设为2的-50次方(即Number.EPSILON * Math.pow(2, -50)
),即如果两个浮点数的差小于这个值,我们就认为这两个浮点数相等。
因此,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
上面的代码为浮点数运算,部署了一个误差检查函数。
6.安全整数和 Number.isSafeInteger()
JavaScript能表示的整数范围为(-2^53,2^53),不在这个区间的整数无法精确表现这个值。
ES6引入了Number.MAX_SAFE_INTEGER
和Number.MIN_SAFE_INTEGER
这两个常量,用来表示这个范围的上下限。数超出了精度范围,在计算机内部,会以9007199254740992的形式储存。
Number.isSafeInteger()
则是用来判断一个整数是否落在这个范围之内。这个函数的实现很简单,就是跟安全整数的两个边界值比较一下。实际使用这个函数时,需要注意。验证运算结果是否落在安全整数的范围内,不要只验证运算结果,而要同时验证参与运算的每个值(可以做差运算)。
7.Math对象的扩展
(1)Math.trunc()
Math.trunc
方法用于去除一个数的小数部分,返回整数部分;对于非数值,Math.trunc
方法内部使用Number
先转化为数值;对于空值和无法截取值的部分,返回NaN
。
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.trunc(NaN); // NaN
Math.trunc('foo'); // NaN
Math.trunc(); // NaN
Math.trunc(undefined) // NaN
(2)Math.sign()
Math.sign
方法用来判断一个数到底是正数、负数、还是零。对于非数值,会先将其转换为数值。如果参数是非数值,会自动转为数值。对于那些无法转为数值的值,会返回NaN
。
它会返回五种值:
参数为正数,返回+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.sign('') // 0
Math.sign(true) // +1
Math.sign(false) // 0
Math.sign(null) // 0
Math.sign('9') // +1
Math.sign('foo') // NaN
Math.sign() // NaN
Math.sign(undefined) // NaN
(3)Math.cbrt()
Math.cbrt
方法用于计算一个数的立方根。对于非数值,Math.cbrt
方法内部也是先使用Number
方法将其转为数值。
Math.cbrt(-1) // -1
Math.cbrt(0) // 0
Math.cbrt(1) // 1
Math.cbrt(2) // 1.2599210498948734
Math.cbrt('8') // 2
Math.cbrt('hello') // NaN
(4)Math.clz32()
JavaScript的整数使用32位二进制形式表示,Math.clz32
方法返回一个数的32位无符号整数形式有多少个前导0。0的二进制形式全为0,所以有32个前导0;1的二进制形式是0b1,只占1位,所以32位之中有31个前导0;1000的二进制形式是0b1111101000
,一共有10位,所以32位之中有22个前导0。如下所示:
Math.clz32(0) // 32
Math.clz32(1) // 31
Math.clz32(1000) // 22
Math.clz32(0b01000000000000000000000000000000) // 1
Math.clz32(0b00100000000000000000000000000000) // 2
clz32
这个函数名就来自”count leading zero bits in 32-bit binary representations of a number“(计算32位整数的前导0)的缩写。
左移运算符(<<
)与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
(5)Math.imul()
Math.imul
方法返回两个数以32位带符号整数形式相乘的结果,返回的也是一个32位的带符号整数。之所以需要部署这个方法,是因为JavaScript有精度限制,超过2的53次方的值无法精确表示。这就是说,对于那些很大的数的乘法,低位数值往往都是不精确的,Math.imul
方法可以返回正确的低位数值。
(0x7fffffff * 0x7fffffff)|0 // 0
上面这个乘法算式,返回结果为0。但是由于这两个二进制数的最低位都是1,所以这个结果肯定是不正确的,因为根据二进制乘法,计算结果的二进制最低位应该也是1。这个错误就是因为它们的乘积超过了2的53次方,JavaScript无法保存额外的精度,就把低位的值都变成了0。Math.imul
方法可以返回正确的值1。
Math.imul(0x7fffffff, 0x7fffffff) // 1
(6)Math.fround()
Math.fround
方法返回一个数的单精度浮点数形式。对于整数来说,Math.fround
方法返回结果不会有任何不同,区别主要是那些无法用64个二进制位精确表示的小数。这时,Math.fround
方法会返回最接近这个小数的单精度浮点数。
Math.fround(0) // 0
Math.fround(1) // 1
Math.fround(1.337) // 1.3370000123977661
Math.fround(1.5) // 1.5
Math.fround(NaN) // NaN
(7)Math.hypot()
Math.hypot
方法返回所有参数的平方和的平方根。如果参数不是数值,Math.hypot
方法会将其转为数值。只要有一个参数无法转为数值,就会返回NaN
。
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
(8)对数方法
Math.expm1()
:Math.expm1(x)
返回e^x - 1
,即Math.exp(x) - 1
。
Math.log1p()
:Math.log1p(x)
方法返回1 + x
的自然对数,即Math.log(1 + x)
。如果x
小于-1,返回NaN
。
Math.log10()
:Math.log10(x)
返回以10为底的x
的对数。如果x小于0,则返回NaN
。
Math.log2()
:Math.log2(x)
返回以2为底的x
的对数。如果x小于0,则返回NaN
。
(9)双曲函数方法
ES6新增了6个双曲函数方法。
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)
8.指数运算符
ES2016 新增了一个指数运算符(**
)。
2 ** 2 // 4
2 ** 3 // 8
指数运算符可以与等号结合,形成一个新的赋值运算符(**=
)。
let a = 1.5;
a **= 2;
// 等同于 a = a * a;
let b = 4;
b **= 3;
// 等同于 b = b * b * b;
注意,在 V8 引擎中,指数运算符与Math.pow
的实现不相同,对于特别大的运算结果,两者会有细微的差异。
Math.pow(99, 99)
// 3.697296376497263e+197
99 ** 99
// 3.697296376497268e+197
上面代码中,两个运算结果的最后一位有效数字是有差异的。
加油!