原文地址:,转载请注明出处!
一、前言
作为一个程序员,我想大家在第一次看到 a = b
的语句时一定是懵逼的。后来才知道 =
在编程语言中是用来赋值的,而不是用来判断两个值是否相等。
那该怎么判断两个值是否相等呢?在 C 或 java 中,是使用 ==
来进行比较,而 JavaScript 就有意思了,除了使用 ==
, 还加了 ===
。
二、区别与选择
-
它们有什么区别?
具体的区别就一句话:
==
在比较时允许进行强制类型转换,而===
不允许。很多人都担心
==
做的事情多一些会不会影响比较的速度,说实话,会的,但影响是微秒级别的,完全可以忽略不计。不难看出,
==
像是===
的一种更深入的扩展,因此,满足===
的值一定满足==
,反之则不成立。 -
该如何选择使用它们?
很多人会建议你坚持使用
===
而不使用==
, 我认为这是不明智的,有些时候,比如说处理后端返回的数据时,你无法保证对方传来的值到你进行比较的时候还是预期的那样,此时我觉得完全在可以适当的使用==
来进行兼容。总的来说,当你真的确定进行比较的值是类型相同的,那就使用
===
,否则,除了几种特殊情况,使用==
并没有什么问题 。
三、===
的比较规则
-
基本类型值的比较
===
的比较规则很简单,对于非对象类型的值,先判断两边的操作数是否是同一类型,如果是,则进行比较,否则,直接返回false
。但有两个例外情况:
NaN === NaN
和+0 === -0
。// 不同类型'12' === 12; // false'a' === true; // falsenull === '12' // falsenull === undefined; // false// 同类型1 === 1; // true'a' === 'a'; // truefalse === false; // truenull === null; // true//特殊情况NaN === NaN; // false+0 === -0 // true复制代码
-
引用类型值的比较
对于包含引用类型值的比较,仍然会先判断两边的数据类型,如果只有一个是引用类型值,则直接返回
false
,如果两边均是引用类型值,则会比较他们的引用地址是否一致。const a = { m: 'string', n: 12};const b = { m: 'string', n: 12};const c = 12;a === b; // falsea === c ; // falseconst d = a;a === d; // true复制代码
四、==
的比较规则
一开始说过了,在使用 ==
进行比较时,运行对两边的操作数进行强制类型转换,那么问题来了,什么情况下会进行转换?不同类型的转换规则又是怎样?
在 MDN
中有这样一张表,用来展示不同类型值进行 ==
判断时的转换规则。
乍一看可能会觉得很乱,但仍然是可以分几种情况来概括这些情况。
在具体分析之前,建议先阅读上一篇文章 ,因为上图中你能看到有诸如 isFalsy()
、ToNumber()
、ToString()
、ToPrimitive
等抽象方法,使用它们只是为了让大家知道强制转换的方向和结果,而这些也都是上一篇文章讲到的内容。
-
Undefined
和Null
与其它类型值的比较我们看前两行和前两列可以发现:它们只和自身及对方相等,与其他类型值比较均返回
false
。 ....这个大概就是传说中的「黑风双煞」吧!大家可能会看到
Object
有一个isFalse()
方法,这个方法是用来判断参数值是否是假值,这个时候大家可能会有疑问了,对象不是都是真值吗?没错,
document.all
就是一个假值对象,虽然已经被新的 JavaScript 标准废弃,但你或许会在老的项目中看到它,记住就好。由于这俩值的特殊性,后面我们说“其他类型”值的时候是排除这俩类型的。
-
Number
类型值与其他类型值比较除了上面的黑风双煞,
Number
算是相等比较时的大哥,谁想和它比较,就得先转成Number
类型。 -
Boolean
类型值与其他类型值比较既然有大哥,肯定得有小弟,而
Boolean
类型值则一马当先,以身作则,将大哥的原则贯彻到底,堪称模范小弟!其他类型值想和
Boolean
值做比较,Boolean
值摇身一变将自己转成了Number
类型,哎,你说,别人能怎么办?!无论别人怎么说,
Boolean
只想做一只安静的舔狗,无怨无悔,一生一世。 -
Object
类型值与其他类型值比较Object
作为 JavaScript 中最会伪装自己的一种类型,在比较之前谁也摸不透它们的真实身份。也正因为此,它们的日子过得不尽相同。在进行比较时,JavaScript 国王会通过
toPrimitive()
方法来揭开他们的真面目,最终你会发现,它们的真实身份可能是任意的一种基本类型。因此,在最终比较时,它们也将以真实身份与其他类型值比较。
-
String
类型值与其他类型值比较对于
String
类型值来说,在进行比较时的日子并不好过,毕竟,黑风双煞惹不起,黑社会说话也得听,唯一能让它感受到生活希望的,就是在与Object
这个变色龙进行比较的时候了。只有
Object
在toPrimitive()
后转为字符串的时候它们可以以字符串的规则进行比较,否则,它们就要面临黑风双煞或是黑社会。
五、==
正确的使用方法
github 上有位大神总结了下面这张图:
我们可以将此当做一份参考。
其实在实际的使用过程中,只要我们避免一些特殊的情况,==
的使用还是安全的。
下面就是七种所谓的特殊情况。
"0" == false; // true -- 晕!false == 0; // true -- 晕!false == ""; // true -- 晕!false == []; // true -- 晕!"" == 0; // true -- 晕!"" == []; // true -- 晕!0 == []; // true -- 晕!复制代码
如何避免?两个原则:
- 如果两边的值中有 true 或者 false,千万不要使用 ==。
- 如果两边的值中有 []、"" 或者 0,尽量不要使用 ==。
六、最后
检验大家成果的时候到了,
- 仔细想想上面七种特殊情况的产生原因。
- 思考下面这些值的比较结果。
[] == ![]; // ?2 == [2]; // ?'' == [null] // ?Number.prototype.valueOf = function() { return 3;};new Number( 2 ) == 3; // ?复制代码