【问题标题】:Short-circuiting an empty array in JS has an unexpected outcome: `[] || true == []`在 JS 中短路一个空数组会产生意想不到的结果:`[] ||真 == []`
【发布时间】:2014-01-07 06:18:37
【问题描述】:

在我的代码中,我假设以下 || 短路是安全的:

var $holidayExpandBarOrOpeningHours = 
                $(".expandBar + .holidayHours_c").prev() || $(".openingHours"); 

但令我惊讶的是,如果我们用 true 语句短路一个空数组,仍然会返回一个空数组。我将在下面使用一些控制台代码进行演示,我的问题是为什么 [] || true 的计算结果为 []

false || "expected"
"expected"
false == []
true
[] || "expected"
[]
typeof([])
"object"
({}) || "expected"
Object {}
({}) == false
false
{} == false
SyntaxError: Unexpected token ==

我的一部分认为这是因为数组是一个 object,其评估结果为真,但如果是这种情况,那么基于 ({}) == true 的人会期望 [] == true

我要注意的最后一件事是使用use 'strict' 模式时的结果是相同的。

【问题讨论】:

  • 空数组不是假的
  • 为了支持@rgthree 的说法,this 文章有一篇关于您可能感兴趣的真值/假值的简单文章。
  • ({}) == true 是假的,就像[] == true 是假的一样。过程是一样的。

标签: javascript


【解决方案1】:

一个空数组是一个对象;强制为布尔值的对象是true。所以

({}) || true; // -> {}
[] || true; // -> []
"" || true; // -> true (empty strings are coerced to false)

旁注 - {} 周围的括号是必需的,以避免将其解析为块。

【讨论】:

  • 感谢您的回复;是的,我考虑过这一点,但由于[] == false 不等于({}) == false,请再次查看我的问题。
  • 请参阅@JohnKugelman 的回答 - == 强制转换为 Number,而不是 Boolean。是的,Javascript 在这方面有点疯狂。
【解决方案2】:

这是因为||==使用不同的规则进行转换。

逻辑或使用ToBoolean,而相等使用ToNumber/ToPrimitive


来自11.11 Binary Logical Operators

3) 如果 ToBoolean(lval) 为真,则返回 lval。

由于ToBoolean([]) 为真,[] || x 的结果为[]。这也是为什么if([]) { /* this runs */ }:JavaScript 中的数组是"truthy" values

来自11.9.3 The Abstract Equality Comparison Algorithm

7) 如果 Type(y) 为 Boolean,则返回比较结果 x == ToNumber(y)

9) [..then] 如果 Type(x) 是 Object 并且 Type(y) 是 String 或 Number, 返回比较结果 ToPrimitive(x) == y.

5) [..then] 如果 Type(x) 是 String 并且 Type(y) 是 Number, 返回比较结果 ToNumber(x) == y.

应用于[] == true 的逻辑是ToNumber(ToPrimitive([])) == ToNumber(true)


以及转化价值:

  • ToBoolean([]) 是真的
  • ToNumber(true) 是 1
  • ToPrimitive([]) 是一个 字符串(来自DefaultValue/toString

所以:

ToNumber(ToPrimitive([])) == ToNumber(true)
ToNumber("") == 1
0 == 1
false

(这与约翰·库格尔曼所说的相差甚远。)


此外,({}) == true 通常为 false,并遵循与上述相同的转换。

在默认环境下,ToPrimtive({}) 返回一个非空字符串(即"[object Object]",按照Object.prototype.toString)。此字符串将在 ToNumber 之后计算为 NaN,使得 NaN == 1;或假。

有关 ToPrimitive 转换的更多详细信息,请参阅 Why an empty Array type-converts to zero? +[]

【讨论】:

    【解决方案3】:

    当转换为布尔值时,[] 为真。

    > !![]
    true
    > ![]
    false
    

    当转换为数字时,[] 为 0。这就是为什么将其与 false 比较返回 true:当比较两个不同类型的值时,JavaScript 先将两者都转换为数字,然后再比较数字。

    > +[]
    0
    > +false
    0
    > +[] == +false
    true
    

    【讨论】:

    • 我很难找到为什么数组 (x) 被转换为== 中的数字。据我所知,这将是ToPrimitive([]) == ToNumber(true) [通过规则 7,然后是 ==] 的结果 - 那么然后是 ToPrimitive([]) == 0(可能通过另一次通过)?但我无法备份。
    • @user2864740 ToPrimitive([]) 产生空字符串,then 开始第 5 步(x 是字符串,y 是数字),空字符串转换为0,通过 ToNumber。 (第 5 步,因为:布尔值在第 7 步变成了数字,而数组在第 9 步变成了字符串。)
    • @apsillers 谢谢,我也发现了! :)
    猜你喜欢
    • 2020-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-16
    • 2019-04-05
    • 1970-01-01
    相关资源
    最近更新 更多