双等于==运算符中的抽象相等比较算法使用

比较运算 x== y,其中 x和 y是值,产生 true或者 false。这样的比较按如下方式进行:

1426852686

  1. 若 Type( x) 与 Type( y)相同,则
    1. 若 Type( x) 为 Undefined,返回 true。
    2. 若 Type( x) 为 Null,返回 true。
    3. 若 Type( x) 为 Number,则
      1. 若 x为 NaN,返回 false。
      2. 若 y为 NaN,返回 false。
      3. 若 x与 y数值相等,返回 true。
      4. 若 x为 +0并且 y为 −0,返回 true。
      5. 若 x为 −0并且 y为 +0,返回 true。
      6. 返回 false。
    4. 若 Type( x) 为 String,则当 x和 y为完全相同的字符序列(长度相等且相同字符在相同位置)时返回 true。 否则,返回 false。
    5. 若 Type( x) 为 Boolean,若 x和 y同时为 true或者同时为 false,则返回 true。 否则,返回false。
    6. 若 x和 y是同一对象的引用,则返回 true。否则,返回 false。
  2. 若 x为 null且 y为 undefined,返回 true。
  3. 若 x为 undefined且 y为 null,返回 true。
  4. 若 Type( x) 为 Number 且 Type( y) 为 String,返回 x== ToNumber( y)。
  5. 若 Type( x) 为 String 且 Type( y) 为 Number,返回 ToNumber( x) == y。
  6. 若 Type( x) 为 Boolean,返回 ToNumber( x) == y。
  7. 若 Type( y) 为 Boolean,返回 x== ToNumber( y)。
  8. 若 Type( x) 为 String 或 Number 且 Type( y) 为 Object,返回 x== ToPrimitive( y)。
  9. 若 Type( x) 为 Object 且 Type( y) 为 String 或 Number,返回 ToPrimitive( x) == y。
  10. 返回 false。

第1条,是要求类型相同的情况。
只需要知道NaN和谁都不==,哪怕自身。
+0和-0是==的。那么+0和-0是===的吗?+0和0是一回事吗?
对此我们需要验证:

console.log(0 === +0);
console.log(0 === -0);
console.log(+0 === -0);

也就是说0、+0和-0这三者在==和===上没什么区别。

第2和3条,应该没谁不清楚的。

console.log(undefined == null);

然而我想说的undefined和null只与undefined和null==,再没有其他的情形。后面会分析。

第4和5条,字符串和数字比较时,要转化为数字,再比较。

console.log(“12” == 12);

转化为数字,这块儿也有点问题。

console.log(‘1x’ == 1);

‘1x’转化为数字后是NaN不是1的,而NaN和任何东西都不等的。
而字符串和数字做比较一个关键点就是,什么字符和0相等?
有好多!

console.log(“0” == 0);
console.log(“000” == 0);
console.log(“” == 0);
console.log(” ” == 0);
console.log(“\n” == 0);
console.log(“\t” == 0);
console.log(“\f” == 0);

第6和7条,有布尔值,要转化为数字。true变成1,false变成0,进而再比较。
这一条涉及了很多。
“1x” == true吗?

console.log(‘1x’ == true);

答案是不等的,因为等价于问”1x”==1吗,当然不等。真不敢想象面试题问这个后,会怎样。
我们更关心的是与false的比较。试想你能答对几道?

console.log(undefined == false);
console.log(null == false);
console.log(0 == false);
console.log(NaN == false);
console.log(“” == false);
console.log(false == false);
console.log({} == false);

这里就涉及到一个问题,除了字符串和数字之外还有什么有可能与0==,答案是只有false。

第8和9条。
[2] == 2吗?

console.log([2]==2);

别看一个是引用类型,一个是基本类型,答案是相等的。为什么?
我们需要了解ToPrimitive这个操作是做什么的?
规范文档是这么讲的:
ToPrimitive是把引用类型转化为基本类型:
引用类型转换为字符串
1.优先调用toString方法(如果有),看其返回结果是否是基本类型,如果是,转化为字符串,返回。
2.否则,调用valueOf方法(如果有),看其返回结果是否是基本类型,如果是,转化为字符串,返回。
3.其他报错。

引用类型转化为数字
1.优先调用valueOf方法(如果有),看其返回结果是否是基本类型,如果是,转化为数字,返回。
2.否则,调用toString方法(如果有),看其返回结果是否是基本类型,如果是,转化为数字,返回。
3.其他报错。
文档规范具体如下(使用的是[[DefaultValue]]内部方法):
而在==中,是转化为数字的。
因为[2].valueOf()是[2]自己本身,不是基本类型,
尝试调用toString,结果是”2″,因此看”2″==2,因此是true。
那么[[[2]]] == 2呢?也是true的,这里就不验证了。
那么[2] == ‘2’时,虽然是与字符的比较,但是也是优先调用valueOf的。
我们可以验证一下:

var a = [2];
a.valueOf = function() {
return 3;
};
console.log(a == ‘3’);

从结果上看,确实调用了valueOf。

第10条,其余情形都返回false。
这回我们可以说为啥undefined和null与其他的数据都不等。

console.log(undefined == 0);
console.log(null == 0);

console.log(undefined == “”);
console.log(null == “”);

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

console.log(undefined == {});
console.log(null == {});

console.log(undefined == []);
console.log(null == []);

以null == 0为例。
首先我们直觉以为null与0==。
我们按算法走一遍,x是null,y是0。
首先x的类型是Null,y的类型是Number,不走1。
同理因为y不为undefined,所以也不走2和3。
同理二者类型也不满足4和5,6和7,8和9,因此最后只能走10,也就是false。
这回清楚了吧,也就是说一遇到与undefined做相等比较都是为false的。null也一样。

最后稍微总结一下,==操作是偏向于转化为数字的。
数字与字符串比较,字符串转化为数字,
有true和false时,转化为数字,
有对象时,按转化为数字的套路,优先调用valueOf。

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

滚动至顶部