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

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

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

  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。

*文章为作者独立观点,不代表上流阁立场
本文由 江风成 授权 上流阁 发表,并经上流阁编辑。转载此文章须经作者同意,并请附上出处(上流阁)及本页链接。原文链接https://www.o6c.com/java/2017/04/09/974.html
发表评论

坐等沙发
相关文章
jar包解压后,修改完配置文件,再还原成jar包
jar包解压后,修改完配置文件,再还原成…
JAVA DES 十六进制加密
JAVA DES 十六进制加密
HTML中Data URI scheme BASE64 文件的拼接头
HTML中Data URI scheme BASE64 文件的拼…
windows BAT 文件 多个命令同步执行
windows BAT 文件 多个命令同步执行
java 中 封装BigDecimal常用计算类MathUtils
java 中 封装BigDecimal常用计算类MathU…
JDBC原生链接Mysql数据根据表映射生成bean实体类
JDBC原生链接Mysql数据根据表映射生成be…
javaweb开发程序员php开发,微信开发。接受定制开发

最新评论