最近发现一个比较神奇的问题如下:
[] == false // true
!![] == true // true
一脸懵逼中。。。
那么,现在就来从开始探索一下这道题的原理
js比较操作
js提供了三中不同的比较操作,分别是:
* 严格相等 ("triple equals" 或 "identity"),使用 ===
* 宽松相等 ("double equals") ,使用 ==
* ES6新出的Object.is()
说一下几种操作的特点与不同。首先,使用=== 与Ojbect.is()进行比较时,是不会进行类型转换的,先判断两边的数据类型,如要两边的数据类型不同,就会直接返回false,再判断数据的值是否相同,这里有个坑点就是对于Number,=== 与Ojbect.is()在处理+0, -0, 与NaN方面有一些不同之处,如下
+0 === -0 // true
Object.is(+0, -0) // false
NaN === NaN // false
Object.is(NaN, NaN) // true
再来说一下==,这个因为涉及到了类型的转换,比较复杂一些。
* 相等操作符比较两个值是否相等,在比较前将两个被比较的值转换为相同类型。在转换后(等式的一边或两边都可能被转换),最终的比较方式等同于全等操作符 === 的比较方式。
* 理解一下两个方法,ToNumber(A),是指在比较前将A转为数字,与 +A(单目运算符+)的效果相同。ToPrimitive(A), 是指通过调用A.toString()或者A.valueOf()方法将A转为原始值(primitive)
然后来看一下表格
可知:
1、Undefined 和 Null:一般情况下,他们只和自身及对方相等,其他情况都会返回false。有个IsFalsy()看起来很奇怪,对象不都应该是返回true么,有啥好判断的?还真不是……有些浏览器会允许一些特殊的对象,如:document.all 等,在某些情况下(相等操作符等)充当undefined的角色,所以,他就会返回false。都是坑爹呢这是……
2、Number: 想与Numbr进行对比,二话不说,你先转成number再BB
3、Boolean:刚想与Boolean做比较,额,他倒是先转成Number了,得嘞,走上了与Number比较的老路
4、Object:可能因为Object比较杂,所以需要先通过ToPrimitive()去找到他的真身以后再进行比较
5、String:优先级最低,因为留给他的对手不多了,一般都是被迫转型,除非对手是String或者ToPrimitive()是String
看起来,类型转换机制还挺复杂的,所以,一般情况下,能用 === 的就尽量不要用 == 了,免得掉进了自己的坑里。什么,非要用==不可?好吧,来看看一下几个案例:
"0" == false; // true
false == 0; // true
false == ""; // true
false == []; // true
"" == 0; // true
"" == []; // true
0 == []; // true
如果以上这些情况你都能理解,嗯,你可以放心的用==了。