关于JS的双等以及不等的规则你还记得吗?

177 阅读3分钟

等于(==)和不等于(!=)

这俩个操作做的工作,没必要多说,应该都知道,我们所需要注意的是,这俩种操作符都会就行隐式的类型转化,也可以说是比较的时候发现俩种类型不能比较,则会通过一些规则进行强制的类型转化,直到可以比较为止。

在转化的过程中会遵循如下规则:

  1. 如果任一操作数是布尔类型,则将其转化为数值再比较。false转化为0,true转化为1。
  2. 如果一个操作数是字符串,另一个操作数为数值,则尝试将字符串转化为数值,在就行比较。
  3. 如果一个操作数是对象,另一个不是,则调用对象的valueOf方法取得其原始值,再根据前面的规则比较。

而在比较的过程中,会遵循如下规则

  1. null和undefined相等
  2. null和undefined不能转化为其他类型的值再进行比较
  3. 如果有任一操作数是NaN,则相等操作符返回false,不相等操作符返回true
  4. 如果俩个操作数都是对象,则比较他们是不是同一个对象,如果俩个操作数都指向同一个对象,则相等操作符返回true。

上面的规则是《高级程序设计(第四版)》给出,仔细品一下上面的规则的话,其实所有的情况都已经涵盖。但是其中转化过程中的第三点说的比较模糊,所以做了一点实际的测试,来有一个更加清除的认识。

为什么说第三点有点模糊呢? 可以在浏览器控制台输入如下代码

({}).valueOf(); // {}

可以看到返回结果依然是一个对象,再根据前面俩条规则判断的话无法判断,那对于({}) == 1这样的表达式是如何判断的呢?下面继续来看。

测试一:

const obj = {
    valueOf() {
        console.log('执行了valueOf方法')

        return 1;
    },
    toString() {
        console.log('执行了toString方法')

        return 2;
    }
}

console.log(obj == 2);  // 执行了valueOf方法 false
console.log(obj == 1);  // 执行了valueOf方法 true

测试二:

const obj = {
    valueOf() {
        console.log('执行了valueOf方法')

        return [];
    },
    toString() {
        console.log('执行了toString方法')

        return '2';
    }
}

console.log(obj == 2);  // 执行了valueOf方法 执行了toString方法 true
console.log(obj == 'a');    // 执行了valueOf方法 执行了toString方法 false

通过上面俩个简单的测试,可以看出,如果一个操作数是对象,另一个不是的话,会调用valueOf获取值,但是获取的值不为基础类型时,则会调用toString方法;如果是基础类型的话,根据前面俩条继续判断。

得出了这些结论后,我们接着看({}) == 1为什么等于false

  • 首先({})会调用valueOf方法,但是得到的仍然是一个对象
  • 因此({})调用toString方法,得到的是一个'[object Object]',然后就变成了'[object Object]' == 1
  • 根据规则的第二条,我们再尝试将'[object Object]'转化为数字
  • Number('[object Object]'),得到的是一个NaN,最后根据比较规则的第三条,得出false

其中字符串转化为数字的过程,我书中没有细说,但是我觉得是用Number()类似的规则做转化的,因为parseInt的话'1[object Object]' == 1这个表达式就为true了,当然这里如果有其他想法的话可以告知一二。

双等号在实际中用到的地方非常非常少,可以说几乎不用,因为存在很多的坑,但是其比较原理还是做一个巩固,当然文中有哪里说的是错的,也欢迎指正。