乍一看,这个咋能相等呢?深入思考就发现不仅可以相等,还有不少方法,下面就来讲讲这些方法都是如何实现的。
一、valueOf && toString
直接上代码:
比较运算分为2种, 一种为严格比较(===),只有类型相等,值也一致时才会为true,否则为false。
另一种为抽象相等也叫宽松相等(==),现将运算数转化为相同类型(隐式转换),再做比较。
看看js中隐式转换的规则,可以参考 JS中的隐式转换
签名:ToPrimitive(input, PreferredType?) //PreferredType: Number 或者 String
流程如下:
- input为原始值,直接返回;
- 不是原始值,如果有symbol.toPrimitive方法,则调用该方法,否则执行3;
- 调用该对象的valueOf()方法,如果结果是原始值,返回原始值;
- 调用valueOf()不是原始值,调用此对象的toString()方法,如果结果为原始值,返回原始值;
- 如果返回的不是原始值,抛出异常TypeError。
其中PreferredType控制是调取valueOf()还是toString()。
ps: Date类型按照String去调用。
再看看 == 比较的转换规则 参考 ECMA抽象等于比较语法
上面的规则抽象成表格如下:
我们上述情况适用于第9条,先把Object转换成原始类型再做比较。拆分开就发生了如下过程:
好了,知道了上面的这些操作规则,那么把toString()改成valueOf()也是完全可以的
二、Array && join
数组对象的隐式转换遵从对象的转换规则,但是在调用数组的toString()方法之前先调用了一下join()方法
所以我们就可以这样写了
三、Symbol.toPrimitive
根据上面第一条规则,我们可以重写对象的symbol.toPrimitive方法。
上面的方法都是通过隐式转换实现,还有一种是直接通过数据劫持。
四、Object.defineProperty
五、Proxy
同样使用proxy也是完全可以的。