js显式类型转换、隐式类型转换及相关==操作符的总结(二)

之前我写过一篇关于==操作符的文章,当时觉得还行,看完《你不知道的javascript 中卷》之后才觉得汗颜。之前的文章错漏百出,也毫无章法,因此参考该书及ECMAScript相关规范,重新整理了一下==操作符的相关规则。

关于对象的抽象化操作(toprimitive)的介绍,可以参考我上一篇文章戳我

在进行==比较时,也会发生隐式类型转换(对象会执行toprimitive操作),这里就介绍一下进行==比较的时候的规则。

一、==的含义

==又叫宽松相等(或称不全等),===又叫严格相等(或称全等)。

以往,关于==和===的区别,我见到的最多的说法是,==比较值,===比较值及类型。

但是,在书中,作者提出,==允许在比较的时候进行类型转换,===不允许在比较的时候进行类型转换。

以上这两种说法,各位自行斟酌。

二、==比较时的规则

ECMAScript 11.9.3(中文版)是这么说的:

  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, 返回comparison x == ToNumber(y)的结果。
  5. 若Type(x) 为 String 且 Type(y)为Number,
  6. 返回比较ToNumber(x) == y的结果。
  7. 若Type(x)为Boolean, 返回比较ToNumber(x) == y的结果。
  8. 若Type(y)为Boolean, 返回比较x == ToNumber(y)的结果。
  9. 若Type(x)为String或Number,且Type(y)为Object,返回比较x == ToPrimitive(y)的结果。
  10. 若Type(x)为Object且Type(y)为String或Number, 返回比较ToPrimitive(x) == y的结果。
  11. 返回false。

下面来个总结。

1、简单值的比较

如果两个值同类型,比较两个值。其中需要特别说明的是,NaN!=NaN。对象的话比较指针。

如果两个值类型不相同,那么:

  1. null==undefined;
  2. null、undefined与其他值的==比较结果均为false;
  3. 如果是字符串与数字比较,则将字符串强制转换成数字(调用Number()),然后返回两个数字比较的结果;
  4. 如果是布尔值与其他值比较,则将布尔值转换成数字,然后返回数字与其他值的比较的结果;

因为参考的是ecma5的规范,没有包括Symbol值。按照我的经验及搜索到的资料,Symbol值与其他类型的值比较时均为false,与同类型(Symbol类型)的值比较时,除for()方法传入相同参数得到的值,即使描述符相同也为false。(这一条如有错误欢迎指正)

    let a=Symbol('aaa');
    let b=Symbol.for('aaa');
    let c=Symbol.for('aaa');
    console.log(a==b)
    console.log(a==c)
    console.log(b==b)

2、对象与简单值的比较

对象与简单值的比较,分以下几种情况:

  1. 如果简单值是nul或者undefined,结果是false;
  2. 如果简单值是字符串或者数字,对对象进行toprimitive操作进行类型转换,类型是number,然后返回比较的结果;
  3. 如果简单类型是boolean,先将boolean值强制转换成数字,然后遵循第二条规则,返回比较的结果;
  4. 如果简单类型是Symbol值,会对对象进行toprimitive操作,类型是number,然后返回比较的结果;
      let a = Symbol.for("aaa");
      let b = Symbol.for("aaa");
      let obj = {
        valueOf() {
          return "aaa";
        },
        toString() {
          return "a";
        }
      };
      let obj1 = {
        valueOf() {
          return a;
        },
        toString() {
          return "a";
        }
      };
      let obj2 = {
        valueOf() {
          return "0";
        },
        toString() {
          return "a";
        }
      };
      console.log(obj == "aaa", "对象执行toprimitive操作,类型是number"); //
      console.log(obj1 == b, "对象执行toprimitive操作,类型是number"); //
      console.log(obj2 == false,"boolean先转换为数字,对象执行toprimitive操作,类型是number");

注意的一点是,包装类型的也是对象,默认情况下,包装类型的对象进行toprimitive的的结果是对应的简单类型的值。但是,如果自己更改了原生对象的原型上的valueOf()方法(Date对象对应的是toString()方法),结果会不同。

    let a=new Boolean(2);
    let b=new Boolean(2);
    a.valueOf=function(){
        return 2
    }
    // Boolean.prototype.valueOf=function(){
    //     return 2
    // }
    console.log(a==2)
    console.log(b==2)

3、Date对象

上一篇文章说过,Date对象有别于其他对象。其他对象进行隐式类型转换时默认类型是number,Date对象默认则是string。那么比较的时候呢?测试一下就知道了。

      let currentDate = new Date();
      let a = currentDate.valueOf();
      let b = currentDate.toString();
      console.log(a == currentDate,"//如果为true则Date对象toprimitive默认类型是number");
      console.log(b == currentDate,"//如果为true则Date对象toprimitive默认类型是string");

所以,Date对象在进行==的时候,进行toprimitive操作的类型是string。

4、特别提醒

需要特别注意的是,==的结果并不能传递。即:a==b,b==c并不能得出a==c。因为进行==比较时,转换的规则会根据值的类型有所不同。

      console.log(0 == "0");
      console.log(0 == "");
      console.log("0" == "");

三、结语

以上就是==比较的规则,ECMAScropt6的规范原文我没找到关于==的解释,所以用的还是ECMAScript5的规则。如有错漏还望指正。

参考资料;ECMAScript规范中文版11.9.3 戳我

                 《你不知道的javascript 中卷》

                   我的上一篇文章:戳我

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值