本文部分内容来自《你不知道的Javascript》关于宽松相等和严格相等部分

一、宽松相等和严格相等

一直以来,使用宽松相等使用的很多,也看了许多文章对其的介绍和区别。

但是看完《你不知道》系列的一篇文章,才发现,自己对宽松相等和严格相等的认识简直就是太肤浅了。

1、 概念

第一个就是概念上的,我对其认识也是文章中说的“误区”认识:

  • == 检查值是否相等,而 === 检查值和类型是否相等

我知道,在进行 == 进行比较的时候,实际上会发生类型转换,但是认识没有那么深刻,而文章给出的正确的解释在我看来才是对 == 最好的解释:

  • == 允许在相等比较中进行强制类型转换,而 === 不允许

2、 性能

我对性能的认识也是局限在,文章中所描述的:

第一种解释(不准确的版本),=== 似乎比== 做的事情更多,因为它还要检查值的类型。
第二种解释中== 的工作量更大一些,因为如果值的类型不同还需要进行强制类型转换

而实际上两者所使用的时间可以忽略不计的,因为:

== 和=== 都会检查操作数的类型。
区别在于操作数类型不同时它们的处理方式不同。

二、相等比较的强制类型转换

既然 == 在进行比较的时候会进行强制类型转换,则在进行转换的时候必然有一个选择,比如 一个NumberString 如果转换,是将 Number 转换成 String 进行字符串大小比较还是反过来进行。

我个人使用最多的情况可能就是:

const a = 41;
const b = '41';
console.log(a == b); // true

进行 == 比较的结果肯定是 true ,但是在比较过程中,是进行 String 还是 Number 比较也是一个问题。

1、 数字和字符串

在进行数字和字符串比较的时候,会将字符串转换成数字类型 ,然后在进行大小的比较。

比如上面的示例。

但是同样的,这和顺序无关,无论是 a == b 还是 b == a ,被转换的都是字符串类型。

2、 其他类型和 Boolean 类型比较

这是我之前没有重视的大坑,因为很少使用 xxx == true 或者 xxx == false 这样的方式进行比较,一般都是直接用 if( ) 进行转换了。

const a = 123;
const b = '123';

console.log(a == true); // false
console.log(a == false); // false
console.log(b == true); // false
console.log(b == false); // false

const c = true;

console.log(a == c); // false

出现上面结果的最直接的原因就是,其他类型在和 Boolean 类型进行比较的时候,默认强制转换的是 Boolean类型 而不是其他类型

因此上面的代码中,true 要么被转换成 1, 要么被转换成 0 (或者相应的字符串形式),而这个是不可能相等的。

上面这句话是存在问题的:

console.log('' == false);

上面这个例子最终输出的是true.

理由:其他类型和bool类型进行比较的时候,首先把bool类型转换为Number类型,然后在进行比较

  • 上面的示例中,首先 false 转换成 0 ,然后 0'' 比较
  • 由于 '' 是字符串,因此会再次进行转换, '' 转换成 0
  • 0==0所以返回true.

但是凡事都有例外:

const x = 1;
const y = 0;
console.log(x == true); // true
console.log(y == false); // true

因为 true 被转换成 1, false 被转换成 0 ,导致上面的两个比较又是成立的。

由于这个大坑存在,所以在进行比较的时候 true 和 false 最好不要出现在条件中。

3、 null == undefined

无论是 null == undefined 还是 undefined == null 结果都是返回 true

意思是:null 和 undefined 可以相互进行隐式强制类型转换

4、 对象

我自己觉得很有意思的代码:(自己想出来的)

const a = {
    name:"ptbird",
    valueOf(){
        return 20;
    },
    toString(){
        return "20";
    }
};
console.log(20 == a); // true
console.log("20" == a); // true

由于valueOf()toString() 都存在,但是是比较操作符,因此和 toString() 关系不大,会使用 valueOf的值。

而第一个比较是同类型,而第二个则是不同类型,因此 "20" 会强制转换为 20, 在进行比较。

对于对象来说,如果修改了valueOf()(包括Array等Object),会对比较的结果产生影响

三、一些大坑

在文章中列举了一些很明显的坑,列表如下:

"0" == null; // false
"0" == undefined; // false
"0" == false; // true         -- 晕!
"0" == NaN; // false
"0" == 0; // true
"0" == ""; // false

false == null; // false
false == undefined; // false
false == NaN; // false
false == 0; // true         -- 晕!
false == ""; // true         -- 晕!
false == []; // true         -- 晕!
false == {}; // false

"" == null; // false
"" == undefined; // false
"" == NaN; // false
"" == 0; // true         -- 晕!
"" == []; // true         -- 晕!
"" == {}; // false
0 == null; // false
0 == undefined; // false
0 == NaN; // false
0 == []; // true         -- 晕!
0 == {}; // false

[] == ![] // true        -- 更晕!

[] == ![] // true 成立的原因:

  1. 首先 [] 本身是 true 的,但是加了 !操作符后,会进行强制类型转换!true,然后返回结果 false
  2. 最后的比较成了 [] == false 这个比较中,也会进行强制类型转换,首先是 Boolean 进行转换,因此 false 被转换成 数字 0,比较变成了 [] == 0
  3. 在新的比较中,[] 被转换成数字 0 (Number([]) = 0 ;) ,所以最后的比较变成了 0 == 0;

因此在上面的比较过程中实际上发生了 3次强制类型转换

根据上面可以的带比较独特的几个比较也就有了解释了:

"" == 0; // true
"" == []; // true 
0 == []; // true 

四、小于等于 仅表示 不大于

最无语的当然还是对象的抽象比较,如下面的例子

    const p1 = {
        age: 20
    }
    const p2 = {
        age: 20
    }
    console.log(p1.valueOf());// {age:20}
    console.log(p2.valueOf());// {age:20}
    console.log(p1.valueOf() == p2.valueOf()); // false
    console.log(p1.age == p2.age) // true
    console.log(p1 == p2); // false
    console.log(p1 < p2); // false
    console.log(p1 > p2); // false
    console.log(p1 <= p2); // true
    console.log(p1 >= p2); // true

首先是 概念的问题:

<= 不代表 小于等于 ,而表示不大于,同样的 >= 表示的是 不小于

传统的认知里面,不大于自然就是小于等于了,然而在进行对象抽象比较的过程中,会复杂的多。

理解了这个概念,就能够知道 p1 >= p2 // true的原因是啥了。

下载.jpg