[] == ![] ?揭晓你不知道的 ==
前言
日常项目开发中,大部分的项目规范会提到使用
===代替==,究其原因,无非是相对来讲===的结果是 更可预测 的,相比之下==伴随着隐式类型转换。两者主要的区别就在于
==用于检查 值 是否相等,而===检查的是 值与类型 是否相等。别小看这简单的两句话,其中伴随的隐式转换可不简单。举个🌰:
1 == "1"到底是1转换成"1"还是"1"转换成1呢?
知其所以然
思考🤔
求相等运算符的结果总是返回Boolean类型,反映运算符所命名的两个操作数之间的关系是否成立。但,你真的知道 == 的工作原理吗?试着看看以下代码的执行结果
undefined == null; // true
NaN == NaN; // false
1 == "1"; // true
1 == true; // true
2 == true; // false
[] == [] // false
"" == [] // true
0 == [] //true
true == [] // false
true == ![] // false
true == !![] // true
[] == ![] // true
"a" == new String("a"); // true
new String("a") == new String("a"); // false
...
如果你对上面的结果一知半解,或者知道结果但是不知道内部是如何转换过来的,那么请继续往下看
同类型比较(🐕==🐶)
关于 a == b ;假设两者类型相同:
1、 那么当 typeof a 为 undefined,又或者两者皆为null,结果为 true;
undeinfed == undefined // true
null == null // true
2、 当typeof a 为 string时,若a、b 是完全相同的字符序列,返回 true;
'abc' == 'abc' // true
3、 当typeof a 为 number时,若 a 或 b 存在1个及以上是 NaN 时,返回 false;否则如果数值相等则为 true,其余情况为 false;
123 == 123 // true
NaN == NaN // false
4、 当typeof a 为 boolean时,若a、b 都为 true 或都为 false 时,返回 true;否则返回 false;
true == true // true
false == false // true
false == true // false
5、 当typeof a 为 object时,若a、b 指向同一个对象,返回 true;若 a、b都为 null 返回 true,否则返回 false;
{} == {} // false
[] == [] // false,千万不可使用 xxx == [] 来判断数组是否为空
new String("a") == new String("a"); // false
let obj = {}
let a = obj
let b = obj
a == b // true
null == null
不同类型比较(🐖==🐕)(重点)
关于 a == b ;假设两者类型不相同:
1、a 、b 中有一个是undefined,另一个是null时,返回 true
undefined == null // true
2、a 、b 中有一个是number,一个是string,那么会将string转化为number再进行比较:
1 == '1' // true,转化成 1 == 1进行比较;'1' == 1 同理
3、 a 或 b 当中存在 boolean时 ,将 boolean 转为number 再进行比较:
1 == true // true,转化成 1 == 1进行比较;
'1' == true // true 转化成 '1' == 1 => 1 == 1
'2' == true // false
'0' == false // true
4、a 或 b 中有一个是object(非null),且另一个为基本数据类型 ,则先调用 object的valueOf方法,若结果为基本数据类型,则返回结果进行比较;否则调用object的toString方法,若结果为基本数据类型,则返回结果进行比较,否则抛出错误
// 优先调用valueOf
"a" == new String("a"); // true, new String('a').valueOf() === 'a'
let obj = {
valueOf(){
return 2
}
}
2 == obj // true
// valueOf没有返回基本类型则调用toString
let obj1 = {
toString(){
return '3'
}
}
3 == obj1 // true
// toString没有返回基本类型,报错
let obj2 = {
toString(){
return {}
}
}
3 == obj2 // 报错 Cannot convert object to primitive value
0 == [] // true 转化为 0 == '' => 0 == 0
5、需要注意的是,按照上述第四种情况,会出现一些令人意想不到的情况
true == [] // false,[] 被转化成'' => 0
true == ![] // false, 转化成 true == !true;
true == !![] // true, 转化成 true == !!true;
// 同理
false == [] // true
false == ![] // true
false == !![] // false
[] == ![] // true 本质上是[] == false; 转换为 '' == false => 0 == 0 => true
这是因为在js中,引用数据类型转化为boolean会被转为true,因此[]加上 ! 之后
会先将[]转为 true,再进行取反,结果就为 false 。
===👬
上面提到全等号检查的是 值与类型,那么当两个值类型不同时结果直接为false,若是基本类型且类型相同时则根据自身值是否相同进行判断。需要注意的是:NaN === NaN 结果是 false。
若两个值皆为 引用类型,则需要判断两者是否指向同一个对象,是则返回 true,否则为 false。
总结
大部分情况下其实使用 == 都是相对安全的,很多情况下也能简化我们的代码。
容易混淆的主要有以下几种情况(这些情况下如果不够明确,那么考虑使用===,这对于后续其他开发者来讲也是有利的):
- 比较的值里面有一边可能是
boolean类型(true/false) - 比较的值里面有一边可能是
0或''或[]
更多时候,如果你能明确知道你写的代码是你想要的结果以及明确其中是怎么转换的,那么==号就是安全的!否则请尽量避免使用==,而是使用===。
相信看到这里的你已经对其中的转换规则有了更加深入的理解!更多相关的细节大家可通过 ES5规范 中的11.9.3节进行了解。
写得不对或不好的地方欢迎大家指正交流~~
转载自:https://juejin.cn/post/7153072391634026527