【问题标题】:why do both if('0'==false) and if('0') evaluate to true in Javascript?为什么 if('0'==false) 和 if('0') 在 Javascript 中都评估为 true?
【发布时间】:2013-05-03 06:40:33
【问题描述】:

所以据我所知,Javascript 中的 if 语句将其条件的结果转换为布尔值,然后像下面这样执行它

if(true) {
    // run this
}

if(false) {
    // do not run this
}

这行得通。但如果我这样做:

if('0' == false) {
    // We get here, so '0' is a falsy value
}

那么我会期待这个

if('0') {
    // We don't get here, because '0' is falsy value
}

但是我得到了

if('0') {
    // We *DO* get here, even though '0' is falsy value
}

那么发生了什么?显然,if 不检查其条件是真值还是假值,而是进行其他转换?

【问题讨论】:

标签: javascript if-statement


【解决方案1】:

这个:

if('0') {
    // We *DO* get here, even though '0' is falsy value
}

检查字符串是否为空或空,而不是它是否为零。任何非空字符串都是真实的。

当你这样做时:

if('0' == false) {
    // We get here, so '0' is a falsy value
}

您要求 JS 引擎进行显式类型转换以尝试匹配两个操作数的类型。这与仅仅询问一个操作数本身是否为真是不同的。

一般来说,如果您几乎总是使用===!==,并且仅在您确切知道在所有情况下会发生什么时才允许类型强制,或者因为您完全了解非常复杂的强制规则,或者因为您知道将出现哪些类型并且您了解这些特定情况。

【讨论】:

    【解决方案2】:

    if ('0' == false):

    Javascript 正在做一些名为 type coercion 的事情。

    按照该链接中的规则,我们遵循规则 7:

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

    调用 ToNumber(false) 给我们一个数字 0。结果现在开始有意义了,但我们还没有完成,因为我们还有一个字符串和一个数字。该过程再次开始,这次我们落入规则 5:

    如果 Type(x) 为 String 且 Type(y) 为 Number,则返回比较结果 ToNumber(x) == y: "2" == 2

    这一次,左边的'0'被转换成一个数字:0。现在,我们终于可以比较两个数字了,因为0等于0,所以结果为真。但是,重要的是要注意,这根本不暗示 '0' 字符串的真/假本质,因为它在比较之前是强制的。

    if('0')

    在这种情况下,没有比较;您只想知道单个值是“真”还是“假”。不使用类型强制,因为字符串可以根据其自身的优点被评估为真或假。使用与之前相同的链接中的规则,我们可以找到以下信息:

    在 JavaScript 中,不仅仅是 JavaScript,我们有所谓的虚假值。它们分别是:0、null、undefined、false、""、NaN。请注意,空字符串为空,因为与 php 示例不同,“0”将被视为 truish

    引号特别有用,因为它专门调用了“0”字符串,但这不是必需的。知道一个空字符串是假的就足够了,而任何其他字符串都是真的,因为不评估字符串的内容并且不执行强制。 0 可能是一个假值,但因为我们评估的是一个字符串而不是强制转换为一个数字,而 '0' 具有某种值,所以它仍然是真的。

    【讨论】:

      【解决方案3】:

      这只是== rules 相当复杂的“陷阱”之一。

      比较 x == y,其中 x 和 y 是值,产生真或假。这样的比较是这样进行的:

      (4) 如果 Type(x) 是 Number 并且 Type(y) 是 String, 返回比较结果 x == ToNumber(y)。

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

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

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

      在这种情况下,这意味着'0' == false首先被强制执行'0' == 0(根据规则#7),然后在第二次通过时,它被强制为0 == 0(根据规则#5),结果为真.

      这个特殊情况有点棘手,因为false ~> 0 而不是'0' ~> true(正如预期的那样)。但是,'0' 本身就是一个真值,其行为可以用上述规则来解释。要在测试中实现严格的真假相等(这与严格相等不同)而在相等期间不进行隐式转换,请考虑:

      !!'0' == !!false
      

      (对于所有值:!falsey -> true!truthy -> false。)

      【讨论】:

        【解决方案4】:

        Javascript 操作符== 做类型转换,基本没用。避免它。

        例如:

        • [] 是真实的,但 [] == falsetrue
        • 1 == "1"[1] == "1"[[1]] == "1"都是真的
        • [1] == [[1]] 然而是假的

        规则很奇怪。例如,在第一种情况下,[] 被转换为"",后者被转换为数字,值为0false 也转换为数字 0。所以最后他们比较相等。

        但是请注意,虽然从空字符串到数字的转换得到0,但parseInt("") 的结果是NaN

        PS:真正有趣的是当你发现[30,20,10,3,2,1].sort() 返回[1,10,2,20,3,30](是的...数字,是的,按字典顺序排列)。不,我不是在开玩笑。

        【讨论】:

        • “基本没用”太过分了。
        • @bfavaretto:我不这么认为。我还没有找到一个重要的用例,其中== 而不是=== 是有意义的。
        • 我能想到的一种情况是与来自 html 输入字段的数字进行比较,而无需 parseInt (当然,只有在您确定输入包含数字时才安全)。不过,我同意“避免它”部分。
        • @6502——我发现完全相反,几乎从不使用===。只有在您真正关心类型相同时才应使用严格相等,这在绝大多数情况下是不必要的。
        猜你喜欢
        • 2019-04-24
        • 1970-01-01
        • 1970-01-01
        • 2013-09-02
        • 2020-08-15
        • 2015-03-15
        • 2015-04-16
        • 2013-06-01
        • 1970-01-01
        相关资源
        最近更新 更多