Bootstrap

从 == 与 === 引发的隐式类型转换思考

众所周知,在JavaScript中,'=='代表相等,而'==='代表全等。我们知道,1=='1'返回true,而1==='1'返回false,其背后的原因为,全等符号判断两边类型不同时会直接返回false,而相等符号会优先进行类型转换,将字符串'1'转变为数值1,从而判断两边相等,那么这背后的转换遵循什么规律呢?

首先,如果一个操作数是字符串,另一个操作数是数字,则先尝试把字符串转换为数字,上文便是活生生的例子,不再赘述。

如果操作数是布尔值,则先转换为数值,其中 false 转为 0,true 转换为 1。

false == 0   // true
true == 1    // true

曾经年少无知的我,还以为true==任何非零的值都会判断正确,真是尴了个尬……

true == 2   // false

究其原因,便是true转换为1了,那自然1不等于2了。

如果两个操作数都是对象,则比较引用地址。如果引用地址相同,则相等;否则不等。

这个也没有什么太大的解释必要,两个定义相似甚至相同的对象,由于他们的引用地址不同,会返回false;如果将一个对象的值直接赋给另一个对象,那么判断这两个对象将返回true。

如果一个操作数是字符串,另一个操作数是对象,则先尝试把对象转换为字符串。

这里有一个很有意思的例子:

a = {}
a == '[object Object]'   // true

首先要知道,对象是如何转换为字符串的呢?

1、先尝试调用toString方法,并返回相应的结果;

2、没有的话尝试调用valueOf方法,并返回相应的结果;

3、都没有则抛出异常。

而a作为一个对象,自然是有自己的toString方法的,并且这个toString方法我们也非常熟悉,它可以用来判断一个值的数据类型,返回'[object type]',其中type是对应的数据类型。而这里的a调用完toString方法后,会返回'[object Object]',两者自然就相等了。

如果一个操作数是数字,另一个操作数是对象,则先尝试把对象转换为数字。

下面有一个很反常的例子:

[1] == 1   // true

what?虽然它们都有1,但是这一眼看去怎么可能相等呢?

别急,让我们看看,对象是如何转换为数字的。(注意,数组的类型就是Object,也就是对象)

1、先尝试调用valueOf方法,并返回相应的结果;

2、没有的话尝试调用toString方法,并返回相应的结果;

3、都没有则抛出异常。

可以看到,和转换为字符串的方法只是反了过来。而数组调用valueOf方法返回的值为它本身,因此继续采用toString方法。这里的toString方法又和上面的不同,数组当中重写了toString方法,内部的原理和join方法相同,因此这里会返回'1',再通过最开始的例子,就可以看到它们是相等的了。

所以,下面这个例子返回的也是true:

[1,2,3] == '1,2,3'   // true

写到这里,我似乎看到了相等符的更多可能性,内部不仅涉及到了隐式转换,也涉及到了不同原型上重写的不同的toString方法,这一块留到下一篇文章再讲。

还有一些特殊的例子,null和undefined不会被转换为其它值,因此它们与0进行判断的时候返回的也是false,大家不要想当然了。然而这两者判断时却是相等的,这个背后的原因我还不清楚,欢迎大家提出自己的见解,目前我只当做一个特例来看待,就如同NaN不会等于它本身一样,当然,使用Object.is()可以判断两个NaN相等。

;