== 运算符隐式转换

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

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

类型不相同时:this

一、x,y 为null、undefined二者中一个 // 返回truespa

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

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

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

== 例子解析

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。继承

[] == !{}
复制代码

解析:

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

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

解析:

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

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

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

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

五、同上能够推导 a == 3也返回true。故最终结果 a == 1 && a == 2 && a == 3返回true