JS填坑系列:数学运算

前言

JS中的数学运算,一直以来都布满了各种坑,比如最常见的就是:0.1+0.2!=0.3。作为前端开发者,我们应该知道如何避开这些坑。下面我们就来看一些可能大家不知道的坑。

max() 和 min()

Math.max() > Math.min();
// false

Math.max() < Math.min();
// true

什么?Math.max()要比Math.min()小。为什么呢?

我们都知道Math.max()用来返回一组数字中的最大值,而如果不传参数,则返回-Infinity(负无穷大)。我们可以在Chrome浏览器看下:

那又有个疑问,为什么不传参数要返回一个-Infinity而不是其他值呢?其实很好理解,Math.max()是要获取传入的参数中最大的那个值,那必然默认的就会是一个最小值,否则不就取到这个默认值了吗?可能其过程如下:

function max() {
    let _max = -Infinity;
    for (let val of arguments) {
        if (val > _max) {
            _max = val
        }
    }
    return _max;
}

而与之相反,Math.min()如果不传参数,返回的是Infinity(正无穷大)。

因为-Infinity < Infinity,所以便有了Math.max() < Math.min()

1 < 2 < 3

1<2<3
// true

3>2>1
// false

是的,你没看错,JS的数学运算就是这么神奇。。。

关键是我们要知道为什么?

因为JavaScript解析器是从左到右执行的,所以1<2<3中会先执行1<2结果为true,然后再比较true<3,等价于Number(true)<3

Number(true);  // 1
Number(true) < 3;  // true

所以1<2<3的结果为true

同理,3>2>1最终会变成Number(true) > 1,很明显会返回false

Number(true);  // 1
Number(true) > 1;  // false

‘5’ + 3

'5' + 3  // 53
'5' - 3  // 2

这个应该比较好理解,之所以加减法表现不一样,是因为-只会用在数学运算中,而+还可以用在字符串拼接中。

所以遇到-会自动将非数字转换为数字,而遇到+时,如果两边的类型不是数字或字符串,会进行一定的类型转换,优先考虑转换为字符串并连接。

[] + {}

[] + {}  // [Object Object]

{} + []  // 0

+[] + {}会进行类型转换,分别调用toString()方法

([]).toString();  // ''
({}).toString();  // [Object Object]

于是就有了最终的结果[Object Object]

那为什么{} + [],结果就变成0呢?

这是因为此处以{}开头会被认为是一个语句块,空表示什么都不做,于是就被忽略了,最终也就变成了一个一元表达式+[]

而一元正号运算符如果位于其操作数前面,计算其操作数的数值,如果操作数不是一个数值,会尝试将其转化成一个数值。所以+[]就等于Number([])结果为0。

所以问题的本质还是在于{}不同于[],它还有其他层面的用途,那么如何让{}被当成是一个对象字面量呢?很简单,加上括号即可:

({}) + []  // [Object Object]

好了,就先总结到这里。

感谢阅读~

如果你还想知道更多JS中数学运算的坑,可以看我之前分享的文章:

JavaScript:为什么3+true=4?