首页 > 为什么 [1] == 1 的结果会是true

为什么 [1] == 1 的结果会是true

就是如果在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

总的来看,似乎是如果只有一个元素,那么就和这一个元素判断是否相等,如果多个就进行正常的判断,请问是这样么?

另外对于这种情况的转化规则是什么?


讨论 js 的 == 操作符没有意义。本来就是一大堆人设的规则,而逻辑是无法进行推导的。


JS是弱类型语言。


js有===这个运算符,同时判断值和类型


不是,是toString()
是先调用valueOf() 但是默认的 valueOf()返回的是对象,所以再去调用toString()

[1] == 1
true

[1,2] == "1,2"
true

Array.prototype.toString = function(){return this.join("")}

[1,2] == "1,2"
false

[1,2] == "12"
true

[1,2] == 12
true

Array.prototype.toString = function(){return 10}

[1,2] == 10
true

[1,2,2] == 10
true

[9] == 9
false

Array.prototype.valueOf = function(){return 11}
[1,2] == 11
true

[1,2] == 10
false

简单说是 比较运算符 == 会在比较之前判断操作数的类型是否相等,如果不相等,就想转换成合适的类型,再比较。

举例:

'1' == 1 // true 



因为比较运算符会先将左操作数由一个字符字面量衍生出一个数学的值,简单说就是字符串‘1’变数字1
再进行比较的时候   1 == 1 

传送门

标准相等操作符(== and !=) 使用 Abstract Equality Comparison Algorithm 去比较两个操作数。当两个操作数类型不相等时,会在比较前尝试将其转换为相同类型。 e.g., 对于表达式 5 == '5', 在比较前会先将左边字符串类型的操作数 5 转换为数字。

严格相等操作符 (=== and !==) 使用 Strict Equality Comparison Algorithm 并尝试对两个相同操作数进行相等比较,如果它们的类型不相等,那么永远会返回false 所以 5 !== '5'。


这是因为 [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)再进行比较。

原文是:

  1. If Type(x) is either String or Number and Type(y) is Object, return the result of the comparison x == ToPrimitive(y).

那么接下来问题就是,Array 如何转换成基本类型?这在标准的 9.1 节有规定,其具体实现细节则写在 8.12.8 节。

在 hint 为 Number 时,标准规定:

  1. 调用对象的 valueOf 方法,如果返回值为基本类型,这个值就是最终值;
  2. 否则,调用 toString 方法,如果返回值为基本类型(字符串是基本类型之一),这个值就是最终值;
  3. 以上皆不可,抛出异常。

对于 Array 来说:

那么,比较 [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 返回的不是基础类型怎么办呢?

javascript// 在 Chrome/42.0.2311.90 验证通过
Array.prototype.toString = function() {
  return {}
}
[1] == 1 // 抛出 TypeError 异常

这说明至少 Chrome 的实现是非常符合标准的,也同时说明,简单将 [1] == 1 理解成 [1].toString() == 1 并不是十分精确。

当然,以上都是吹毛求疵,了解一下就好啦。


因为js品味很差...

【热门文章】
【热门文章】