JavaScript “==” 的奇妙冒险

JavaScript “==” 的奇妙冒险

Scroll Down

JavaScript "==" 的奇妙冒险

JavaScript数据类型

最新的 ECMAScript 标准定义了 8 种数据类型:

  • Boolean
  • Null
  • Undefined
  • Number
  • BigInt
  • String
  • Symbol
  • Object (引用类型)

== 两边操作数类型不同,导致的类型转换现象

在这之前,先来看一组奇怪的东西:

image-20200830134552224

image-20200830135614773

image-20200830153656690

JS在 ”==“ 情况下的比较规则

在两个操作数类型不相等的情况下

  1. 如果有一个操作数是布尔值,则在比较相等性之前先将其转化为数值: false是0,而true为1
  2. 如果一个操作数是字符串,另一个操作数是数值,在比较相等性之前先将字符串转化位数值
  3. 如果一个操作数是对象,则调用对象的toString() 方法,转为toString()方法的返回值,接下来再按1,2的规则来

0 == false ,"" == false 和 1 == ture

这些都是根据上面规则进行转化,将字符串或者true 转化为数值来比较 自然就是true

[] == false 和 {} == false

[] == false 所以为 true 是因为 空数组 toString() 方法出来的是一个空字符串,相当于 ”“ == false 再通过规则1,2,便可以化为 0==0

所以比较为 ture

{} == false 为 false 则是因为 空对象**toString()**方法 出来的字符串为 "[object Object]",所以比较出来为空 false

如下图

image-20200830142355390

但是好像大部分对象在没有重构toString方法的时候,都是输出的 "[object Object]"对吧?

所以,更奇妙的事情来了

image-20200830143219475

无论对象内容是什么,只要跟 "[object Object]" 做比较,都会是true

接着如果我们对toString 进行重构,将其改为返回 ”我是一个对象“,就会发现这时候与 "[object Object]"比较起来就不相等了

此时与”我是一个对象“进行比较才会相等

那如果我们返回false 呢?

image-20200830143640441

可以发现,如果这时候进行与false进行双等判断,返回为true ,也就说此刻相当于false == false

那么,众所周知,数组也是一个对象,那么快乐的双等它又来了:

image-20200830145422551

当我们给 arr1 赋值一个空数组后,这时候它与false 进行判断为 true

但是当我们改变该数组的 toString方法以后,这就是和上面对象的判断一致了,必须要转为字符串

诚然这里我们是去改变了arr1的属性,但是如果我们去改变 arr1 的原型也是一样的 如下图

image-20200830150307481

当然,不建议去改原型,这会导致所有的数组的toString方法发生改变,造成污染,污染如下图所示

image-20200830151744802

== 两边操作数类型相同,导致的现象

== 两边操作数类型如果一致的话,那便是调用了 ===,进行比较的。所以该种情况下,调用 == 和 === 效果其实都是一样的

那么先上来一个好玩的:

image-20200830152035903

image-20200830153330347

这又是什么奇怪的玩意?

[] == [] : false 的原因

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title></title>
    <script>
        var arr1 = [];
        var arr2 = [];
    </script>
</head>

<body></body>
</html>

我们可以简单的创建两个数组,分别为arr1和arr2,通过谷歌浏览器打开,使用 Heap snapshot(堆快照)功能来获取arr1和arr2的内存地址(基于VM的虚拟机内存地址)如下图所示

image-20200830152911356

image-20200830152939242

其中 arr1 的地址为 @35171 ,arr2地址为@35173

=== 在两边操作数都为对象的时候,便是去比较这两个对象的地址,[] == [] 实际上创建了两个数组,自然这两个的地址页不一致,比较结果为false

image-20200830154043372

那如果我们创建一个中间变量 arrx = [] ,自然 此刻堆 arr1和arr2进行判断后,结果自然是true 了,因为他们时候的内存是相等的

[] == ![] : true 的原因

​ 其实这应该是 属于 == 两边操作符不同的内容,为什么呢?

我们可以来看看 js 中 八大类型的中关于 !的功能:

image-20200830154429967

从上图可以发现所有的空值中,作为对象空值的!非常特殊,它为false!

其实从上面的堆快照截图中不难发现,对象的空值并不是传统意义上的空值,而是一个引用类型指向空对象的一种值

例如 arr1=[] 的实际值是@35171 ,而@35171才是指向堆空间中空数组的地址值,在栈空间中,是没有这个空数组的,

而***!其实是对栈空间中值的判断*** ,无论的Null,false,"",还是 0,他们在栈空间中的实际二进制都是一长串的0,但是@35171是一个地址,这是一个值,它不是0,所以 ![]和!{},才会变成false

因此 [] == ![] 实际上就是 [] ==fasle.

再结合上述 JS在 ”==“ 情况下的比较规则,所以 [] == ![] 的值才会是 true