JavaScript 中的相等和全等之谜
前言
我们都知道 JS 有两种判断是否相等的运算符,一种是相等 ==
,还有一种是全等 ===
。理清楚两者的区别,对日后程序的开发和维护都有很重要的作用。
什么?你已经懂了,觉得这很简单?那么先来看一道题吧。
下面的 a 要怎样赋值,才能使 if 判断为真,打印出 a ?
js
// var a = ?
if (a == 'red' && a == 'green' && a == 'blue') {
console.log(a);
}
你或许会惊讶,这怎么可能,判断条件里面的 a
怎么可能等于不同的值...看完后面的内容,你将豁然开朗。
全等 ===
对于全等 ===
,这是我们开发最常使用的判断相等方式。
- 第一步,判断比较对象的类型是否相同,若类型不同则返回
false
。 - 若类型相同,则进行第二步,判断其值是否相等,若相等则返回
true
,并且不调用任何该对象的方法。
全等 ===
比较具体规则如下:
比较的对象 | 是否相等 |
---|---|
Number | 若都为数值,且值相同,则相等;只要出现了 NaN ,则不相等 |
String | 若都是字符串,且各个字符都相同,则相等,否则不相等 |
Boolean | 若均为 true 或均为 false ,则相等,否则不相等 |
Function | 当引用同一个函数的时候才会相等 |
Object | 当引用同一个对象的时候才会相等 |
null | 若两个值都是 null 则相等 |
undefined | 若均为 undefined 则相等 |
数组 | 当两数组引用指向同一地址则相等 |
函数 | 当两函数引用指向同一地址则相等 |
双等号 ==
对于双等号 ==
,涉及到隐式转换,至于为什么,这就要问 JS 之父 Brendan Eich 了。
转换规则如下:对于两个比较对象
- 若有一个是数字型字符串,有一个是数字,则将字符串转换为相应的数值再比较,两者数值相等则相等。js
console.log('123' == 123); // true
- 若有一个是布尔型,则将布尔型转换为相应的数值再比较:
true
为1
,false
为0
。jsfalse == 0 // true true == '1' // true
- 若有一个是一个对象,而另一个不是对象,则该对象要先执行内部的
valueOf
或toString
方法进行转换,然后再比较。(即转换为对象的原始类型)jsconst obj = { valueOf: function () { return 123; } } console.log(obj == 123); // true
- 若两个都是对象,则不进行转换,而是判断其引用是否指向同一地址,若指向相同则相等。js
let obj1 = {age: 18}; let obj2 = obj1; obj2.age = 20; console.log(obj1 == obj2); // true
- 若有一个为对象(
String()
、Number()
、Symbol()
),则将该对象转换为相应的原始类型再比较。jslet numObj = new Number(123); console.log(numObj == 123); // true
- 只要有一个操作数为
NaN
,则不相等,返回false
。jsconsole.log(NaN == NaN); // false
undefined
和null
是相等的,且比较的时候不进行转换。jsundefined == null // true
- 若两个均为数组/函数,则仅当两者引用指向同一地址时相等。js
let a1 = [1,2,3]; let a2 = a1; a2.push(4); a1 == a2 // true
- 若一个对象为只有一个元素的数组,而另一个不是数组,则比较的时候取该数组的原始类型(当数组只有一个元素的时候),即拿该数组的第一个元素来直接比较。经验证,比较的过程中该数组会执行
toString()
或valueOf
方法。js['apple'] == 'apple' // true
案例
回到本文开头的那个问题,是不是有思路了?
js
// var a = ?
if (a == 'red' && a == 'green' && a == 'blue') {
console.log(a);
}
没错,a
肯定是一种复杂数据类型,这里我们假设 a
为对象。那么 a
肯定有一个属性为数组,存着 red
、green
、blue
三个字符串。然后,按照上节讲的转换原理,每次进行 ==
比较的时候,都改变 toString
或 valueOf
方法的返回值,问题迎刃而解。
一个参考答案:
js
var a = {
i: 0,
colors: [`red`, `green`, `blue`],
valueOf: function () {
return this.colors[this.i++];
}
}
思考:数组也是一种复杂数据类型,那么 a
有没有可能是数组呢?