在 ES6 之前,number类型的数据在操作运算方面其实存在很多问题。

比如说,在 ES5 中没有一个方法,可以让你直接判断一个数字是否为整数。于是你自己必须手动编写一个判断是否为整数的方法,但由于js存在弱类型(隐式)转换,你又得考虑种种情况。是不是觉得很麻烦?

另外,两个或者多个值的运算,可能会得到一个非数字的结果,即 NaN。这里要注意,NaN 在js中的数据类型虽然是 number,但是它是一个特殊的值,它并非表示一个非数字。它不与任何值相等,也与自身也不相等。

回到刚才,如果你要判断这个运算结果,你可能会用 isNaN:

console.log(0/0); // NaN
console.log(isNaN(0/0)); // true

但是:

console.log(isNaN('abc')); // true

通过上面的代码,你会很奇怪。为什么 isNaN('abc') 返回值是 true,但它明明就是字符串 abc,而不是 NaN 啊。这肯定是不对的!

针对上面所说,来吧,看看ES6 做了什么!

一、Number 新增方法

为了改善上述的状况,也为了避免一些全局方法满天飞。ES6 在 Number 对象上新增了一些方法,旨在消除之前数字运算的一些问题。而且,在使用 Number.*() 类似数字操作方法时,大家都知道是基于数字类型的操作,这样也比较直观。

以下列举一些比较常用的:

1.1 Number.isInteger()

该方法判断一个数是否为整数,返回值为布尔值。这个方法不会对非数字转换为数字,所以如果传入的参数不是数字,则直接返回 false。

console.log(Number.isInteger(10)); // true
console.log(Number.isInteger('10')); // false
console.log(Number.isInteger(10.1)); // false
console.log(Number.isInteger(-10)); // true
console.log(Number.isInteger('abc')); // false
console.log(Number.isInteger(true)); // false

1.2 Number.parseInt()

该方法将小数转换为整数,返回值为整数。其功能和之前的 parseInt() 等价,这个方法首先会对非数字尝试着转换为数字,如果传入的参数不能被转换为数字,则直接返回 NaN

console.log(Number.parseInt(10)); // 10
console.log(Number.parseInt('10')); // 10
console.log(Number.parseInt(10.1)); // 10
console.log(Number.parseInt(-10)); // -10
console.log(Number.parseInt('abc')); // NaN
console.log(Number.parseInt(true)); // NaN

1.3 Number.parseFloat()

该方法将数字转换为小数,返回值为一个浮点型数字。其功能和之前的 parseFloat() 等价,这个方法首先会对非数字尝试着转换为数字,如果传入的参数不能被转换为数字,则直接返回 NaN

console.log(Number.parseFloat(10)); // 10
console.log(Number.parseFloat('10')); // 10
console.log(Number.parseFloat('10.3a')); // 10.3
console.log(Number.parseFloat(10.1)); // 10.1
console.log(Number.parseFloat(-10)); // -10
console.log(Number.parseFloat('abc')); // NaN
console.log(Number.parseFloat(true)); // NaN

1.4 Number.isNaN()

该方法用于判断一个值是否为 NaN,返回值为布尔值。这里要注意,NaN 与任何值、甚至它自己本身都不相等。

console.log(Number.isNaN(NaN)); // true
console.log(Number.isNaN(Number.NaN)); // true

console.log(0/0); // NaN
console.log(Number.isNaN(0/0)); // true

console.log(Number.isNaN(10)); // false
console.log(Number.isNaN('10')); // false
console.log(Number.isNaN('abc')); // false
console.log(Number.isNaN({})); // false
console.log(Number.isNaN(true)); // false

不过要提醒的是,Number.isNaN() 功能和之前的 isNaN() 略有不同。前面只要不是 NaN 就返回 false,但后者是只要不是 数字 ,才返回 false 。

console.log(isNaN(1)); // false
console.log(isNaN(NaN)); // true
console.log(isNaN('abc')); // true

console.log(Number.isNaN(1)); // false
console.log(Number.isNaN(NaN)); // true
console.log(Number.isNaN('abc')); // false

1.5 Number.isFinite()

该方法用于判断一个值是否为 有穷数,返回值为布尔值。这个方法不会强制将一个非数字的参数转换成数字,也就说如果传入的参数不是数字,则直接返回 false。

console.log(Number.isFinite(1)); // true
console.log(Number.isFinite(Infinity)); // false
console.log(Number.isFinite(-Infinity)); // false
console.log(Number.isFinite(NaN)); // false
console.log(Number.isFinite(true)); // false

1.6 Number.EPSILON

该静态属性是 ES6 新增的一个极小的常量。它相当于一个衡量标准,如果某个值小于这个衡量标准,则表示这个值是在允许的误差范围内。

console.log(Number.EPSILON); // 2.220446049250313e-16
console.log(0.3 - 0.2); // 0.09999999999999998
console.log(0.3 - 0.2 < Number.EPSILON); // false
console.log(0.1 + 0.2 - 0.3); // 5.551115123125783e-17
console.log(0.1 + 0.2 - 0.3 < Number.EPSILON); // true

因为js是基于浮点数来设计的,所以才会出现上述小数点相减不能对应值的情况。如果可以,对于小数点的运算,尽量先放大 N 倍,进行运算后,再缩小 N 倍,从而得到正确的运算结果。

1.7 Number.isSafeInteger()

js中规定,整数的精确范围在 正负2的53次方 这个范围之间(不包含最大值和最小值)。如果参与运算的值超过或者小于它,则会得到一个不正确的值。先来看下这个范围的具体数值:

console.log(Math.pow(2, 53)); // 9007199254740992
console.log(Math.pow(2, 53) + 1); // 9007199254740992
console.log(Math.pow(-2, 53)); // -9007199254740992
console.log(Math.pow(-2, 53) - 1); // -9007199254740992

为了方便表示这个最大值和最小值,ES6 直接在 Number 上新增了两个静态属性,即常量 Number.MAX_SAFE_INTEGERNumber.MIN_SAFE_INTEGER

console.log(Number.MAX_SAFE_INTEGER); // 9007199254740991
console.log(Number.MIN_SAFE_INTEGER); // -9007199254740991

如果一个数字极大,或者极小的值参与了运算,要保证它运算结果不出错,即需要先对它进行检查。而 Number.isSafeInteger 便是检查某个整数是否在 Number.MIN_SAFE_INTEGERNumber.MAX_SAFE_INTEGER 的这样一个安全范围内。如果是则返回 true。

console.log(Number.isSafeInteger(1)); // true
console.log(Number.isSafeInteger(1.5)); // false
console.log(Number.isSafeInteger(Number.MAX_SAFE_INTEGER + 1)); // false
console.log(Number.isSafeInteger(Number.MIN_SAFE_INTEGER - 1)); // false

二、Math 新增方法

为了更方便数字之间的运算,ES6 中对Math对象新增很多方法,在这,介绍一些比较常用的:

2.1 Math.trunc()

该方法用于去除一个数的小数部分,返回值为整数值。如果传入的参数是一个非数字,则该方法会先将它转换成数字(如果可以),再返回对应的值。

console.log(Math.trunc(1)); // 1
console.log(Math.trunc(1.5)); // 1
console.log(Math.trunc(-1.7)); // -1
console.log(Math.trunc(true)); // 1
console.log(Math.trunc(false)); // 0
console.log(Math.trunc({})); // NaN
console.log(Math.trunc(NaN)); // NaN

2.2 Math.sign()

该方法用于判断一个数是正数、负数或者是零,它的返回值有以下情况:

  • +1 参数是正数
  • -1 参数是正数
  • 0 参数是0
  • -0 参数是-0
  • NaN 参数是不能转换成数字的值

如果传入的参数是一个非数字,则该方法会先将它转换成数字(如果可以),再返回对应的值。

console.log(Math.sign(2)); // 1
console.log(Math.sign(-1.7)); // -1
console.log(Math.sign(true)); // 1
console.log(Math.sign(false)); // 0
console.log(Math.sign(0)); // 0
console.log(Math.sign(-0)); // -0
console.log(Math.sign({})); // NaN
console.log(Math.sign(NaN)); // NaN

2.3 Math.cbrt()

该方法用于计算一个数的立方根,返回值是运算后的结果。如果传入的参数是一个非数字,则该方法会先将它转换成数字(如果可以),再返回对应的值,如果不能转换成数字,则直接返回 NaN 。

console.log(Math.cbrt(3)); // 1.4422495703074083
console.log(Math.cbrt(-1)); // -1
console.log(Math.cbrt(0)); // 0
console.log(Math.cbrt(true)); // 1
console.log(Math.cbrt(false)); // 0
console.log(Math.cbrt('8')); // 2
console.log(Math.cbrt('abc')); // NaN
console.log(Math.cbrt(NaN)); // NaN

当然了,这个方法也可以用 Math.pow(base, exponent) 来代替。其中 base 表示底数,exponent 为 幂。这样看来,此方法好像更通用:

console.log(Math.pow(3, 2)); // 9
console.log(Math.pow(3, 1/2)); // 1.7320508075688772
console.log(Math.pow(3, 1/3)); // 1.4422495703074083

2.4 Math.hypot()

该方法用于计算所有参数平方之和的平方根,返回值是运算后的结果。如果传入的参数是一个非数字,则该方法会先将它转换成数字(如果可以),再返回对应的值,如果不能转换成数字,则直接返回 NaN 。

console.log(Math.hypot(3, 4)); // 5
console.log(Math.hypot(1, 2, 3)); // 3.741657386773941
console.log(Math.hypot(0)); // 0
console.log(Math.hypot(true, 0)); // 1
console.log(Math.hypot(false, 0)); // 0
console.log(Math.hypot('3', 4)); // 5
console.log(Math.hypot('abc', 1)); // NaN

2.5 Math.imul()

该方法用于计算两个参数相乘,返回值是运算后的结果。

这里有两种情况会直接返回 0:

  • 传入的参数只有一个
  • 传入的参数中有不能被转换成数字的值

来看下代码:

console.log(Math.imul(3, 4)); // 12
console.log(Math.imul(1, 2, 3)); // 2
console.log(Math.imul(true, 1)); // 1
console.log(Math.imul(false, 0)); // 0
console.log(Math.imul('3', 4)); // 12
console.log(Math.imul('abc', 1)); // 0
console.log(Math.imul(3)); // 0

2.6 Math.fround()

该方法用于将参数转换为离它最近的单精度浮点数形式的数字,返回值是单精度浮点数形式的数字。如果传入的参数是一个非数字,则该方法会先将它转换成数字(如果可以),再返回对应的值,如果不能转换成数字,则直接返回 NaN 。

console.log(Math.fround(3)); // 3
console.log(Math.fround(1.337)); // 1.3370000123977661
console.log(Math.fround('1.337')); // 1.3370000123977661
console.log(Math.fround(1.5)); // 1.5
console.log(Math.fround(true)); // 1
console.log(Math.fround('abc')); // NaN