<script> console.log([] == false, !![] == false);// true false console.log([] === false, !![] === false);// false false console.log([] == []);// false var a = []; console.log(a == !!a);//fasle </script>
先解析[] == false为什么是true?
他是经历了这个过程最终才为true的。
([] == false) ----> ([] === +0) ----> (“”== +0) ----> (+0 == +0) ---> true
别惊讶,下面我慢慢来分析。
<hr/>
当js引擎解析到[] == false 的时候,会解析执行左右表达式,并分别取出执行结果的值,上述分别为数组对象和false。然后将数组设置为x,false设置为y执行下面的这个
抽象比较算法
在执行抽象相等比较算法的过程中,会发现会将xy操作数进行隐式类型转化的,这也是==运算符副作用的体现。
对于 [] == false的问题应该关注上述步骤的78910步骤。
因为[]和false不是同一类型,所以执行到8的时候会将false调用toNumber()内部方法转化成数字,然后在执行抽象相等比较算法。
toNumber()会将false转化成+0.
<hr/>
然后将[] == +0.继续进行比较算法,执行到10 之后开始使用toPrimitive( )对[]进行转化。
ToPrimitive()转化方法如下:
ToPrimitive()
toPrimitive方法的目的就是将输入的参数转化成非对象类型。
对于任何的对象,比如[]讲调用自身的DefaultValue内部方法,同时可以传入一个期望的类型,一般是数组或者字符串,在 - ++ -- 等运算符为数字 而+ 可能为字符串。但是这里==没有明确期望的类型。所以在DefaultValue中会做相应的处理。
<hr/>
DefaultValue处理过程:
先不着急判断[].DefaultValue值是什么,先解读一下这个算法。
如果期望类型hint为字符串,那么:
先调用备操作对象的toString方法,[get]方式获得,所以会在原型链中查找,如果找到,是一个可以调用的被定义的方法的话,则将对象作为this调用这个方法。否则如果得到值为原始值,则直接返回。
为什么这里要多一步的到值是否可调用判断呢?因为toSTring实在原型链中查找的,所以可以通过对对象的构造函数的prototype属性重写tostring方法得到想要的效果。
如果没有得到原始值,则再调用valueOf方法过程和toString一样,最终如果都不是原始值,则抛出异常。
如果期望类型为数字类型,则先调用valueOf后调用toString。
最重要的是,如果没有明确知道期望类型的话,除非是Data类型默认期望为字符串。其他对象默认为数字处理,也就是说先调用valueOf方法后调用toString方法。
所以,[] 也就明白了实现调用这个数组的valueOf方法如果不是返回原始类型,则调用toString方法。
<hr/>
[]继承了Array的prototype方法,所以执行的是Array.prototype.valueOf( ),但是Array很遗憾的是没有实现valueOf方法,所以很遗憾,根据原型链,最终调用Object.prototype.valueOf
方法。
但是Object.prototype.valueOf返回的是一个对象。不是原始类型还是继续调用Array.prototype.toString()方法。
Array.prototype.toString()
所以他应该调用join方法的,没有传入参数的情况下,返回的是使用,分割的分别调用每一个元素toString的字符串拼接,因为[]中没有元素所以返回的应该是空的字符串。
所以最终变成了”” == 0;
根据抽象比较算法45会将空字符串调用toNumber方法转化成数字 ,最终变成这样 +0 == +0;
然后再调用抽象比较算法。+0和+0是同一类型都是数字,并且有-0和+0相等所以 最终返回true.
对于为什么 [] == []为false,!![] == false为false可以试着根据上述过程进行进一步的分析。