就是如果在console中写入
[1] == 1
他返回的竟然是 true
让我很不解,一个数组和数字比较,他是怎么转化的呢?直接将数组转换成什么呢?
对此,我又进行了如下的测试
[2] == 1
false
[2] == 2
true
[1,3] == 1
false
[1,3] == 2
false
[1,3] == 3
false
['a'] == 'a'
true
['a','b'] == 'a'
false
['a','b'] == 'ab'
false
总的来看,似乎是如果只有一个元素,那么就和这一个元素判断是否相等,如果多个就进行正常的判断,请问是这样么?
另外对于这种情况的转化规则是什么?
这是因为
[1]
在和1
进行比较的时候,首先会被转成数字类型,而转成数字类型在实现上又是通过new Number()
来完成的。所以,
[1] == 1
会变成(new Number([1])).valueOf() == 1
。同时,
Number
的构造函数其实是接受一个字符串作为参数的,加上[1].toString() === "1"
,所以new Number([1])
相当于写new Number("1")
,于是很显然(new Number([1])).valueOf()
就是1
了。当然啦,上面那些都是从浏览器实现的角度来说明问题,其实之前就有人问过和答过几乎一样的问题,重复这个论调太 low。接下来,我还是从 ECMAScript 262 的标准角度来解答,看看为什么浏览器会实现成这样,没耐心的同学可以略过了。
要通过
==
比较值,且运算符两边的变量类型一个是 Number 另一个是对象,javascript 标准的 11.9.3 节规定应该将对象使用ToPrimitive
这个抽象操作(abstract operation)将对象转换成基本类型(primitive)再进行比较。原文是:
那么接下来问题就是,
Array
如何转换成基本类型?这在标准的 9.1 节有规定,其具体实现细节则写在 8.12.8 节。在 hint 为
Number
时,标准规定:valueOf
方法,如果返回值为基本类型,这个值就是最终值;toString
方法,如果返回值为基本类型(字符串是基本类型之一),这个值就是最终值;对于
Array
来说:valueOf
返回是Array
本身,所以不符合第 1 条;toString
返回的时"1"
,符合第 2 条,因此ToPrimitive
的结果就是"1"
。那么,比较
[1] == 1
就变成比较"1" == 1
了。对于这种比较,标准的 11.9.3 节规定的很明白,就是ToNumber("1") == 1
,注意这里的ToNumber
也是个抽象操作,并非实际函数,具体规则在标准的 9.3.1 节定义,简单说就是通过类似new Number()
的算法将字符串变成数字,毫无疑问"1"
应该变成数字1
。因此,
[1] == 1
是 true,而[1, 2] == 1
相当于"1,2" == 1
结果就是 false 了。补充说明一下,为什么 @zonxin 的答案从现象上来说差不多正确,但实际上没那么简单。
从我的答案可看出,
ToPrimitive
最终是调用了toString
来获得字符串值并和数字进行比较,所以一般来说把[1] == 1
理解成[1].toString() == 1
是没问题的。可问题是,假如
toString
返回的不是基础类型怎么办呢?这说明至少 Chrome 的实现是非常符合标准的,也同时说明,简单将
[1] == 1
理解成[1].toString() == 1
并不是十分精确。当然,以上都是吹毛求疵,了解一下就好啦。