JS中捉摸不透的==(宽松等于)

首先来看一个有意思的面试题:

if(a == 3 && a == 4){
    //...
}

第一眼看到这个面试题我是拒绝的,这个等式根本不会成立,怎么会存在一个值既等于3并且还同时等于4呢?根本不可能。

但是在神奇的javascript中这个a是存在的。(对javascript要永远怀着一颗敬畏的心)

var i = 3;
var a = new Object();

a.valueOf = function(){
    return i++;
}

if(a == 3 && a == 4){
    console.log('等式成立了'); // 打印了
}

简单一看这个面试题有点故弄玄虚,谁会这样写代码?(我之前的想法)

但是这其中的知识点很有用,并且不是很好掌握。

其中的主要知识点就是宽松等于(==)涉及到的隐式类型转换。在日常开发中总会被提醒尽量不要使用宽松等于,在相等比较时尽可能的使用严格等于。但是为什么呢?其实通过上面的面试题就可以看出来,宽松等于太神奇了(晦涩难懂,莫名其妙,坑太多),当然这是对于不太了解宽松等于类型转换的我来说的。接下来则会不自量力的尽力来解释一下类型转换和宽松等于。

首先对于 == 和 === 的区别常被解释为 == 并不检查数据类型,=== 检查数据类型。但是这个说法并不完全正确。相对正确的说法是 == 允许数据进行类型转换而 === 并不允许。第一种说法貌似是 === 做了更多的事情,但事实却不是这样的。

== 的几种情况分别是

  1. 两个值类型相同则比较值

    1.1 NaN不等于自身

    1.2 +0 等于 -0

    1.3 两个对象指向同一个值则相等(不发生强制类型转换)

    1.4 === 对于对象的比较同1.3

  2. 数字和字符之间的比较

  3. Boolean和其他之间的比较

  4. 对象和非对象之间的比较

数字和字符串之间的比较

一个String类型值和一个Number类型值之间比较则将String类型值按照 转换为Number表转为Number类型。

var a = '1';
var b = 1;

console.log(a == b); // true 字符‘1’被转换成了数字1再作比较则相等
console.log(a === b); // false 并没有对字符'1'数据类型转换,数据类型不同则不相等

Boolean类型值和其他类型值之间的比较

一个Boolean类型值和一个其他类型值之间比较则将Boolean类型值按照 转换为Boolean表转换为Boolean类型。

var a = true;

console.log(a == 1); // true转换成了数字1再作比较则相等

Object和其他类型值之间的比较

一个Object类型值和一个其他类型值之间比较则将Object类型值按照如下步骤转化:

  1. 该对象如果有valueOf方法则调用该方法
  2. 若该valueOf的返回值是基本类型则用作比较
  3. 若valueOf的返回值不是基本类型则调用toString方法
  4. 若toString方法返回基本类型值则用作比较
  5. 若toString返回值不是基本类型则报错
var a = {
    valueOf: function(){
        return 1;
    },
    toString: function(){
        return 2;
    }
};

console.log(a == 1); // true 调用a.valueOf获得返回值再比较
var a = {
    valueOf: function(){
        return '1';
    },
    toString: function(){
        return 2;
    }
};

console.log(a == 1); // true

以上代码当对象a和数字1作比较调用valueOf方法获得字符串‘1’,这时变成了字符串’1’和数字1作比较,根据字符串和数字比较的规则,将字符串转换成数字等到数字1,然后两个数字1作比较得出相等。

当没有valueOf方法或者valueOf方法不返回基本类型值的时候则调用toString方法。

var a = {
    toString: function(){
        return 1
    }
};

console.log(a == 1); // true

到这里开篇的那道面试题则不难理解了,宽松等于中对象和其他类型比较时涉及到了隐式强制类型转换,首先会调用valueOf方法,如果有必要还会调用toString方法来获取值来进行比较。

Null和Undefined之间的比较

在宽松等于比较中Null类型值只和自身还有Undefined类型值相等。

console.log(null == undefined); // true

console.log(null == false); // false

console.log(undefined == false); // false

console.log(null == ''); // false

console.log(undefined == ''); // false

console.log(null == 0); // false

console.log(null == ''); // false

几个宽松等于的坑

console.log(![] == []); // true
// 取反的优先级高于 ==,所以![]转为false,false转为0,[]调用valueOf得到[],所以调用toString得到‘’,然后''转为0,得到相等

console.log(false == []); // true 
//false转为 0,[]根据上面的步骤转为0,得到相等

"0" == false; // true 注意"0"并不是假值但是这里却是相等的,因为 false 转为 0,变成了数字和字符比较,字符串"0"转为了数字0得到相等

宽松等于中值a与Boolean作比较并不是比较值a是否为真或假,而是值a与转换过后的Boolean值(0或1)作比较。

参考

你不知道的javascript(中卷)

猜你喜欢

转载自blog.csdn.net/lettertiger/article/details/79441160