美文网首页Web前端之路程序员
从[] == ![] 看隐式强制转换机制

从[] == ![] 看隐式强制转换机制

作者: Annnnnn | 来源:发表于2017-08-31 18:02 被阅读53次

    写在最前

    本次分享一下通过ES5规范来总结如何准确的计算“==”的执行结果。由于规范是枯燥无味的,所以作者试图总结了其中的规律,并希望可以让读完这篇文章的读者不再去“死记硬背”==的结果是什么,而是通过几次简单的计算便心有成竹的得出结论!

    欢迎关注我的博客,不定期更新中——

    JavaScript小众系列开始更新啦

    ——何时完结不确定,写多少看我会多少!这是已经更新的地址:

    这个系列旨在对一些人们不常用遇到的知识点,以及可能常用到但不曾深入了解的部分做一个重新梳理,虽然可能有些部分看起来没有什么用,因为平时开发真的用不到!但个人认为糟粕也好精华也罢里面全部蕴藏着JS一些偏本质的东西或者说底层规范,如果能适当避开舒适区来看这些小细节,也许对自己也会有些帮助~文章更新在我的博客,欢迎不定期关注。

    先看实验代码

    2 == true               //false
    2 == false              //false
    [] == false             //true
    "0" == false            //true
    [] == ![]               //true 神奇吧
    

    我相信大部分的童鞋看着这种等式一般的反应都是xxx是真值,可以转换为true。xxx是假的所以是false!好的摒弃这种想法吧,不然也不会出现这么多神奇的结果了,我们需要做的是通过一步步计算来得出结论。

    前置知识

    这部分知识属于真·死记硬背,因为你问我为什么,我只能说规范就是这么定义的。

    假值

    为什么提到假值,而不是真值是因为真值真的是太!多!了!但是假值只有以下这么几个:

    • undefined
    • null
    • false
    • +0、-0、NaN
    • ""

    除此以外别的值做强制类型转换的时候都是真值,so记住就好。
    PS:有兴趣的同学可以试试new Number(0)之类的通过对象包装的假值的结果,不过这并不常用故不属于本次讨论范畴。

    !

    ! 这个运算符,会进行显式强制转化,将结果转化为布尔值即true或false。例如:

    ![] //false
    !1  //false
    !0  //true
    

    以此类推来进行显式的强制转换

    undefined == null

    参考规范11.9.3节抽象相等比较算法可得出
    undefined == null 为true的结论。
    PS:本次计算规则为抽象相等比较算法的总结,细节可参考上文11.9.3节规范。

    ToPrimitive

    image
    这是规范9.1节的内容,简单来说你只需要知道如果某个对象([], {})之类的要进行隐式类型转换,那么里面会顺序执行两个操作。即x.valueOf().toString()。这里有一个不常用的点要注意。我说的是对象类型进行“隐式”类型转化,如果是显式则不是如此。看下例子:
    var a = {
        valueOf: () => 1,
        toString: () => 233
    }
    a + ""     // 1
    String(a)  // 233
    

    隐式转化是按照先valueOf后toString的顺序执行,如果显式调用会直接执行oString,不过显式调用在js中覆盖率没有隐式的多,知道即可。

    计算 x == y 规则

    x,y如果类型相同

    这个部分相信有问题的同学百度一下就好。数字的比大小,字符串比大小。里面需要小心的就是NaN != NaN 以及 对象如何比较大小?([1] != [1])

    重点:x,y类型不同

    x,y一方为布尔值

    如果x,y其中一个是布尔值,那么对这个布尔值进行toNumber操作。发现问题了么童鞋们,来看下面代码:

    42 == true   // false
    

    不了解规范的会认为,42是真值啊!42会转换为true!你别说如if(42){}这个42确实是真值。但是我们现在在讨论“==”下的转换,那么请记住规范规定了:类型不同时若一方是布尔值,是对布尔值进行类型转化即true => 1,之后我们就可以理解为什么42不等于true了因为1!= 42

    x,y为数字和字符串

    将字符串的一方进行toNumber()操作,这个不难理解哈

    x,y一方为对象

    将对象进行ToPrimitive()操作。如何操作见上文。

    计算示例代码结果

    2 == true

    true => 一方为布尔值:true => 1
    2 != 1
    

    2 == false

    true => 一方为布尔值:false => 0
    2 != 0
    

    [] == false

    1、[]为对象: ToPrimitive([]) => [].valueOf().toString() => ""
    2、false为布尔:false => 0
    3、等式变为:"" == 0
    4、一方为数字,一方为字符
        Number("") => 0
        => 0 == 0
    

    "0" == false

    1、false为布尔:false => 0
    2、等式变为:"0" == 0
    3、一方为数字,一方为字符
        Number("0") => 0
        => 0 == 0
    

    终极版 [] == ![]

    1、左侧[]为对象: ToPrimitive([]) => [].valueOf().toString() => ""
    2、右侧![]先进行显式类型转换:false(除了上文提到的假值剩下都是真值)
    3、等式变为: "" == false
    4、一方为布尔:false => 0
    5、等式变为:"" == 0
    5、一方为数字,一方为字符
        Number("") => 0
        => 0 == 0
    

    所以你会发现这些看起来神奇的效果,不过是一步步按照规则进行强制转换罢了。希望以后大家再遇到这种神奇等式的时候不要靠记忆谁是谁,而是一步步推算你会发现结果也不过如此,扮猪吃老虎罢了~

    参考文献

    1. ES5规范
    2. 《你不知道的JavaScript(中卷)》

    最后

    惯例po作者的博客,不定时更新中——
    有问题欢迎在issues下交流,捂脸求star=。=

    相关文章

      网友评论

        本文标题:从[] == ![] 看隐式强制转换机制

        本文链接:https://www.haomeiwen.com/subject/fsmqjxtx.html