美文网首页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=。=

相关文章

  • 知行社的前端早读课 第16期

    一个 QA 工程师走进酒吧,点了 -1 杯啤酒,然后酒吧爆炸了。 《从[] == ![] 看隐式强制转换机制》 概...

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

    写在最前 本次分享一下通过ES5规范来总结如何准确的计算“==”的执行结果。由于规范是枯燥无味的,所以作者试图总结...

  • JavaScript中比较运算的详细总结

    前言 在javascript开发中,比较操作是十分常见的。由于显式/隐式强制类型转换机制的存在,我们在使用比较运算...

  • JavaScript 常见面试题分析(四)

    01 强制类型转换和隐式类型转换 强制:parseInt、parseFloat、toString隐式:if、逻辑运...

  • JavaScript面试题-码动未来

    1.例举3种强制类型转换和2种隐式类型转换? 强制(parseInt,parseFloat,number)隐式(=...

  • 类型转换

    我们能够从代码中看出哪些地方是显式强制类型转换,而隐式强制类型转换则不那么明显,例如: 数组的默认 toStrin...

  • Java 学习笔记_2

    1、隐式转换 和 强制类型转换 隐式转换: 又叫自动类型转换。由系统自动完成的类型转换. 从存储范围小的类型到存储...

  • 前端基础js篇

    1.强制类型转换和隐式类型转换 强制转换:parseInt()、parseFolat()、Number()、Str...

  • js总结(2.转换)

    转换 1.隐式转换结论 2.显示转换/强制转换

  • 第十六天vue面试题

    1.列举三种强制类型转换和两种隐式类型转换 强制(parseInt(),parseFloat(),Number()...

网友评论

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

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