33 个 JavaScript 核心概念系列(四): == 与 ===

本文详细解析了JavaScript中==与===的区别,探讨了它们的比较规则与使用场景,帮助开发者理解何时应该使用哪种操作符,以避免常见的类型转换陷阱。

原文地址:落明的博客,转载请注明出处!

一、前言

作为一个程序员,我想大家在第一次看到 a = b 的语句时一定是懵逼的。后来才知道 = 在编程语言中是用来赋值的,而不是用来判断两个值是否相等。

那该怎么判断两个值是否相等呢?在 C 或 java 中,是使用 == 来进行比较,而 JavaScript 就有意思了,除了使用 == , 还加了 ===

二、区别与选择

  1. 它们有什么区别?

    具体的区别就一句话:== 在比较时允许进行强制类型转换,而 === 不允许。

    很多人都担心 == 做的事情多一些会不会影响比较的速度,说实话,会的,但影响是微秒级别的,完全可以忽略不计。

    不难看出,== 像是 === 的一种更深入的扩展,因此,满足 === 的值一定满足 ==,反之则不成立。

  2. 该如何选择使用它们?

    很多人会建议你坚持使用 === 而不使用 ==, 我认为这是不明智的,有些时候,比如说处理后端返回的数据时,你无法保证对方传来的值到你进行比较的时候还是预期的那样,此时我觉得完全在可以适当的使用 == 来进行兼容。

    总的来说,当你真的确定进行比较的值是类型相同的,那就使用 ===,否则,除了几种特殊情况,使用 == 并没有什么问题 。

三、=== 的比较规则

  1. 基本类型值的比较

    === 的比较规则很简单,对于非对象类型的值,先判断两边的操作数是否是同一类型,如果是,则进行比较,否则,直接返回 false

    但有两个例外情况:NaN === NaN+0 === -0

    // 不同类型
    '12' === 12; // false
    'a' === true; // false
    null === '12' // false
    null === undefined; // false
    
    // 同类型
    1 === 1; // true
    'a' === 'a'; // true
    false === false; // true
    null === null; // true
    
    //特殊情况
    NaN === NaN; // false
    +0 === -0 // true
    复制代码
  2. 引用类型值的比较

    对于包含引用类型值的比较,仍然会先判断两边的数据类型,如果只有一个是引用类型值,则直接返回 false,如果两边均是引用类型值,则会比较他们的引用地址是否一致。

    const a = {
        m: 'string',
        n: 12
    };
    const b = {
        m: 'string',
        n: 12
    };
    const c = 12;
    
    a === b; // false
    a === c ; // false
    
    const d = a;
    a === d; // true
    复制代码

四、== 的比较规则

一开始说过了,在使用 == 进行比较时,运行对两边的操作数进行强制类型转换,那么问题来了,什么情况下会进行转换?不同类型的转换规则又是怎样?

MDN 中有这样一张表,用来展示不同类型值进行 == 判断时的转换规则。

乍一看可能会觉得很乱,但仍然是可以分几种情况来概括这些情况。

在具体分析之前,建议先阅读上一篇文章 显式 (名义) 与 隐式 (鸭子)类型转换 ,因为上图中你能看到有诸如 isFalsy()ToNumber()ToString()ToPrimitive 等抽象方法,使用它们只是为了让大家知道强制转换的方向和结果,而这些也都是上一篇文章讲到的内容。

  1. UndefinedNull 与其它类型值的比较

    我们看前两行和前两列可以发现:它们只和自身及对方相等,与其他类型值比较均返回 false ....这个大概就是传说中的「黑风双煞」吧!

    大家可能会看到 Object 有一个 isFalse() 方法,这个方法是用来判断参数值是否是假值,这个时候大家可能会有疑问了,对象不是都是真值吗?

    没错,document.all 就是一个假值对象,虽然已经被新的 JavaScript 标准废弃,但你或许会在老的项目中看到它,记住就好。

    由于这俩值的特殊性,后面我们说“其他类型”值的时候是排除这俩类型的。

  2. Number 类型值与其他类型值比较

    除了上面的黑风双煞,Number 算是相等比较时的大哥,谁想和它比较,就得先转成 Number 类型。

  3. Boolean 类型值与其他类型值比较

    既然有大哥,肯定得有小弟,而 Boolean 类型值则一马当先,以身作则,将大哥的原则贯彻到底,堪称模范小弟!

    其他类型值想和 Boolean 值做比较,Boolean 值摇身一变将自己转成了 Number 类型,哎,你说,别人能怎么办?!

    无论别人怎么说,Boolean 只想做一只安静的舔狗,无怨无悔,一生一世。

  4. Object 类型值与其他类型值比较

    Object 作为 JavaScript 中最会伪装自己的一种类型,在比较之前谁也摸不透它们的真实身份。也正因为此,它们的日子过得不尽相同。

    在进行比较时,JavaScript 国王会通过 toPrimitive() 方法来揭开他们的真面目,最终你会发现,它们的真实身份可能是任意的一种基本类型。

    因此,在最终比较时,它们也将以真实身份与其他类型值比较。

  5. String 类型值与其他类型值比较

    对于 String 类型值来说,在进行比较时的日子并不好过,毕竟,黑风双煞惹不起,黑社会说话也得听,唯一能让它感受到生活希望的,就是在与 Object 这个变色龙进行比较的时候了。

    只有 ObjecttoPrimitive() 后转为字符串的时候它们可以以字符串的规则进行比较,否则,它们就要面临黑风双煞或是黑社会。

五、== 正确的使用方法

github 上有位大神总结了下面这张图:

我们可以将此当做一份参考。

其实在实际的使用过程中,只要我们避免一些特殊的情况,== 的使用还是安全的。

下面就是七种所谓的特殊情况。

"0" == false; // true -- 晕!
false == 0; // true -- 晕!
false == ""; // true -- 晕!
false == []; // true -- 晕!
"" == 0; // true -- 晕!
"" == []; // true -- 晕!
0 == []; // true -- 晕!
复制代码

如何避免?两个原则:

  1. 如果两边的值中有 true 或者 false,千万不要使用 ==。
  2. 如果两边的值中有 []、"" 或者 0,尽量不要使用 ==。

六、最后

检验大家成果的时候到了,

  1. 仔细想想上面七种特殊情况的产生原因。
  2. 思考下面这些值的比较结果。
[] == ![]; // ?
2 == [2]; // ?
'' == [null] // ?

Number.prototype.valueOf = function() {
 return 3;
};
new Number( 2 ) == 3; // ?

复制代码
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值