Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
Aaaaaaaty opened this issue Aug 19, 2017 · 1 comment
Open

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

Aaaaaaaty opened this issue Aug 19, 2017 · 1 comment

Comments

@Aaaaaaaty
Copy link
Owner

Aaaaaaaty commented Aug 19, 2017

写在最前

本次分享一下通过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(中卷)》

最后

不定时更新中——
有问题欢迎在issues下交流。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants