== 运算符隐式转换

413 阅读2分钟

==的类型转换主要分为两类,x、y类型相同时,和类型不相同时。

类型相同时,没有类型转换,主要注意NaN不与任何值相等,包括它自己,即NaN !== NaN。

类型不相同时:

1、x,y 为null、undefined两者中一个 // 返回true

2、x、y为Number和String类型时,则转换为Number类型比较。

3、有Boolean类型时,Boolean转化为Number类型比较。

4、一个Object类型,一个String或Number类型,将Object类型进行原始转换后,按上面流程进行原始值比较。

== 例子解析

var a = {
  valueOf: function () {
     return 1;
  },
  toString: function () {
     return '123'
  }
}
true == a ;// true;

解析:

首先,x与y类型不同,x为boolean类型,则进行ToNumber转换为1,为number类型。 接着,x为number,y为object类型,对y进行原始转换,ToPrimitive(a, ?),没有指定转换类型,默认number类型。 而后,ToPrimitive(a, Number)首先调用valueOf方法,返回1,得到原始类型1。 最后 1 == 1, 返回true。

[] == !{}

解析:

1、! 运算符优先级高于==,故先进行!运算。 2、!{}运算结果为false,结果变成 [] == false比较。 3、等式右边y = ToNumber(false) = 0。结果变成 [] == 0。 4、比较变成ToPrimitive([]) == 0。 进行原始值转换,[]会先调用valueOf函数,返回this。 不是原始值,继续调用toString方法,x = [].toString() = ‘’。 故结果为 ‘’ == 0比较。 5、根据上面第5条,等式左边x = ToNumber(‘’) = 0。 所以结果变为: 0 == 0,返回true,比较结束。

const a = {
  i: 1,
  toString: function () {
    return a.i++;
  }
}
if (a == 1 && a == 2 && a == 3) {
  console.log('hello world!');
}

解析:

1、当执行a == 1 && a == 2 && a == 3 时,会从左到右一步一步解析,首先 a == 1,会进行ToPrimitive(a, Number) == 1。

2、ToPrimitive(a, Number),按照上面原始类型转换规则,会先调用valueOf方法,a的valueOf方法继承自Object.prototype。返回a本身,而非原始类型,故会调用toString方法。

3、因为toString被重写,所以会调用重写的toString方法,故返回1,注意这里是i++,而不是++i,它会先返回i,在将i+1。故ToPrimitive(a, Number) = 1。也就是1 == 1,此时i = 1 + 1 = 2。

4、执行完a == 1返回true,会执行a == 2,同理,会调用ToPrimitive(a, Number),同上先调用valueOf方法,在调用toString方法,由于第一步,i = 2此时,ToPrimitive(a, Number) = 2, 也就是2 == 2, 此时i = 2 + 1。

5、同上可以推导 a == 3也返回true。故最终结果 a == 1 && a == 2 && a == 3返回true