代码之家  ›  专栏  ›  技术社区  ›  Xavi Arik G

为什么2==[2]在JavaScript中是空的?

  •  163
  • Xavi Arik G  · 技术社区  · 15 年前

    我最近发现 2 == [2] 在JavaScript中。事实证明,这种怪癖有两个有趣的后果:

    var a = [0, 1, 2, 3];
    a[[2]] === a[2]; // this is true
    

    var a = { "abc" : 1 };
    a[["abc"]] === a["abc"]; // this is also true
    

    更奇怪的是,这同样有效:

    [[[[[[[2]]]]]]] == 2; // this is true too! WTF?
    

    这些行为似乎在所有浏览器中都是一致的。

    你知道为什么这是一种语言特征吗?

    以下是该“功能”更疯狂的后果:

    [0] == false // true
    if ([0]) { /* executes */ } // [0] is both true and false!
    
    var a = [0];
    a == a // true
    a == !a // also true, WTF?
    
    9 回复  |  直到 4 年前
        1
  •  136
  •   Christoph    15 年前

    您可以在ECMA规范中查找比较算法(ECMA-262第三版中针对您的问题的相关章节:11.9.3、9.1、8.6.2.6)。

    如果将涉及的抽象算法翻译回JS,那么在计算时会发生什么 2 == [2] 基本上是这样的:

    2 === Number([2].valueOf().toString())
    

    哪里 valueOf() for array返回数组本身,单元素数组的字符串表示形式是单个元素的字符串表示形式。

    这也解释了第三个例子 [[[[[[[2]]]]]]].toString() 2 .

    === .

    第一个和第二个示例更容易理解,因为属性名称总是字符串,所以

    a[[2]]
    

    相当于

    a[[2].toString()]
    

    这只是

    a["2"]
    

        2
  •  10
  •   Chetan S    15 年前

    这是因为 ==

    [2] 与数字比较时,转换为数字为2。试试一元 + [2]上的运算符。

    > +[2]
    2
    
        3
  •  10
  •   Shawn    15 年前
    var a = [0, 1, 2, 3];
    a[[2]] === a[2]; // this is true
    

    在等式的右侧,我们有a[2],它返回一个值为2的数字类型。在左边,我们首先创建一个新数组,其中一个对象为2。然后我们调用一个[(数组在这里)]。我不确定它的计算结果是字符串还是数字。2或“2”。让我们先看字符串大小写。我相信[“2”]会创建一个新变量并返回null。空!==2.所以让我们假设它实际上隐式地转换为一个数字。a[2]将返回2。2和2在类型(so==works)和值上匹配。我认为它隐式地将数组转换为数字,因为[value]需要字符串或数字。看起来数字的优先级更高。

    顺便说一句,我想知道是谁决定了优先顺序。是因为[2]的第一项是数字,所以它会转换为数字吗?或者,当将数组传递到[array]时,它会尝试先将数组转换为数字,然后再转换为字符串。谁知道呢?

    var a = { "abc" : 1 };
    a[["abc"]] === a["abc"];
    

    在本例中,您正在创建一个名为a的对象,其中有一个名为abc的成员。等式的右边很简单;它相当于a.abc。这返回1。左侧首先创建[“abc”]的文字数组。然后通过传入新创建的数组来搜索对象上的变量。因为这需要一个字符串,所以它将数组转换为字符串。现在计算为a[“abc”],等于1。1和1是相同的类型(这就是为什么===有效)和相等的值。

    [[[[[[[2]]]]]]] == 2; 
    

    这只是一个隐式转换在这种情况下不起作用,因为存在类型不匹配。

        4
  •  8
  •   Dan Hook    15 年前

    对于 == Doug Crockford 建议始终使用 === . 它不做任何隐式类型转换。

    === ,隐式类型转换在调用相等运算符之前完成。

        5
  •  7
  •   Alexander Abramov    15 年前
    [0] == false // true
    if ([0]) { /* executes */ } // [0] is both true and false!
    

    这很有趣,事实上[0]并不是既正确又错误

    [0] == true // false
    

    这是javascript处理if()运算符的有趣方式。

        6
  •  6
  •   Ólafur Waage    15 年前

    一个项目的数组可以视为项目本身。

    这是因为duck类型。因为“2”==2==2]甚至更多。

        7
  •  3
  •   eyelidlessness    15 年前

    要为其他答案添加一点细节。。。当比较 Array Number ,Javascript将转换 具有 parseFloat(array) . 您可以自己在控制台中尝试(例如Firebug或Web Inspector),看看有什么不同 排列 将值转换为。

    parseFloat([2]); // 2
    parseFloat([2, 3]); // 2
    parseFloat(['', 2]); // NaN
    

    对于 s parseFloat 在上执行操作 的第一个成员,并放弃其余成员。

    编辑:根据Christoph的详细信息,它可能在内部使用较长的表单,但结果始终与 parseFloat 作为速记,以确定它将如何转换。

        8
  •  2
  •   Jaseem    14 年前

    您在每种情况下都要比较两个对象。。不要使用==,如果你在考虑比较,你是在考虑==,而不是==。==通常会产生疯狂的效果。在语言中寻找好的部分:)

        9
  •  1
  •   n4m31ess_c0d3r Suneel    9 年前

    编辑 问题部分:

    第一个例子

    [0] == false // true
    if ([0]) { /* executes */ } // [0] is both true and false!
    

    根据上面Christoph的回答,第一次将[0]类型转换为原语值,我们得到了“0”( [0].valueOf().toString()

    "0" == false
    

    现在,将布尔(false)类型转换为数字,然后将字符串(“0”)类型转换为数字

    Number("0") == Number(false)
    or  0 == 0 
    so, [0] == false  // true
    

    至于 if 语句,如果if条件本身中没有显式比较,则该条件的计算结果为 价值观

    只有 6虚假价值观 :false、null、未定义、0、NaN和空字符串“”。任何不是虚假价值的东西都是真实的价值。

    如果 声明评估为true&执行该语句。


    第二个例子

    var a = [0];
    a == a // true
    a == !a // also true, WTF?
    

    再次键入将值强制转换为基元,

        a = a
    or  [0].valueOf().toString() == [0].valueOf().toString()
    or  "0" == "0" // true; same type, same value
    
    
    a == !a
    or  [0].valueOf().toString() == [0].valueOf().toString()
    or  "0" == !"0"
    or  "0" == false
    or  Number("0") == Number(false)
    or  0 = 0   // true