JavaScript 的相等规则

    ES6 中有三种内建的支持来决定某个 x 和 某个 x 是“相同”的. 它们是: 相等或者"双等"(==), 严格相等(全等)或者"triple equals" (===), 以及 (注意, 是在 ES6 中新添加的. ES6之前出现的相等和严格相等没有任何变化.)


    为了演示, 下面是我们在使用的三种类型的一致性比较:

    x == y
    x === y, y)

    简单来说, 当进行两个值的比较时, 相等运算符将可能执行一个类型转换; 而严格相等运算符将执行没有类型转换情况下的一致性比较(所以如果两个不同类型的值进行严格相等比较时总是返回 false); 最后, 类似于严格相等===运算符,除了两个特例情况:就是NaN和NaN比较,以及+0和-0比较, 比如, NaN) 总是返回 true. (Comparing NaN with NaN ordinarily—i.e., using either double equals or triple equals—evaluates to false, because IEEE 754 says so.)

    Do note that the distinction between these all have to do with their handling of primitives; 它们都没有比较在结构上的概念相似性. 对于任何拥有相同的结构但是是不同的对象本身的非原始对象 x 和 y(string, boolean, number, undefined, null等是原始对象), 上面提到的三种一致性比较均返回 false.


    let x = { value: 17 };
    let y = { value: 17 };
    console.log(, y)); // false;
    console.log(x === y);         // false
    console.log(x == y);          // false

    Abstract equality, strict equality, and same value

    In ES5, the comparison performed by == is described in Section 11.9.3, The Abstract Equality Algorithm. The === comparison is 11.9.6, The Strict Equality Algorithm. (去看看这些. 它们是简明易读的. 提醒: 请先阅读严格相等部分.) ES5 also describes, in Section 9.12, The SameValue Algorithm for use internally by the JS engine. It's largely the same as the Strict Equality Algorithm, except that and 9.12.4 differ in handling Numbers. ES6 simply proposes to expose this algorithm through

    We can see that with double and triple equals, with the exception of doing a type check upfront in, the Strict Equality Algorithm is a subset of the Abstract Equality Algorithm, because–7 correspond to–f.

    A model for understanding equality comparisons?

    在ES6之前, 你可能听说过相等和严格相等, 并且严格相等是前者的增强版本. 比如, 一些人认为相等是严格相等的一个扩展版本, 因为通过类型转换前者能比后者做更大范围的比较(e.g., so that 6 == "6"). 然而, 也有一些人认为严格相等是相等的一个增强版本, 因为它要求两个操作数是相同的类型. Which one is better depends on one's idea of which is the baseline.

    However, this way of thinking about the built-in sameness operators is not a model that can be stretched to allow a place for ES6's on this "spectrum". isn't simply "looser" than double equals or "stricter" than triple equals, nor does it fit somewhere in between (i.e., being both stricter than double equals, but looser than triple equals). We can see from the sameness comparisons table below that this is due to the way that handles NaN. Notice that if, NaN) evaluated to false, we could say that it fits on the loose/strict spectrum as an even stricter form of triple equals, one that distinguishes between -0 and +0. The NaN handling means this is untrue, however. Unfortunately, simply has to be thought of in terms of its specific characteristics, rather than its looseness or strictness with regard to the equality operators.

    Sameness Comparisons
    x y == ===
    undefined undefined true true true
    null null true true true
    true true true true true
    false false true true true
    "foo" "foo" true true true
    { foo: "bar" } x true true true
    0 0 true true true
    +0 -0 true true false
    0 false true false false
    "" false true false false
    "" 0 true false false
    "0" 0 true false false
    "17" 17 true false false
    new String("foo") "foo" true false false
    null undefined true false false
    null false false false false
    undefined false false false false
    { foo: "bar" } { foo: "bar" } false false false
    new String("foo") new String("foo") false false false
    0 null false false false
    0 NaN false false false
    "foo" NaN false false false
    NaN NaN false false true

    When to use versus triple equals

    Aside from the way it treats NaN, generally, the only time's special behavior towards zeroes is likely to be of interest is in the pursuit of certain metaprogramming schemes, especially regarding property descriptors when it is desirable for your work to mirror some of the characteristics of Object.defineProperty. If your use case does not require this, it is suggested to avoid and use === instead. Even if your requirements involve having comparisons between two NaN values evaluate to true, generally it is easier to special-case the NaN checks (using the isNaN method available from previous versions of ECMAScript) than it is to work out how surrounding computations might affect the sign of any zeroes you encounter in your comparison.

    Here's an inexhaustive list of built-in methods and operators that might cause a distinction between -0 and +0 to manifest itself in your code:

    - (unary negation)

    It's obvious that negating 0 produces -0. But the abstraction of an expression can cause -0 to creep in when you don't realize it. For example, consider:

    let stoppingForce = obj.mass * -obj.velocity

    If obj.velocity is 0 (or computes to 0), a -0 is introduced at that place and propogates out into stoppingForce.

    It's possible for a -0 to be introduced into an expression as a return value of these methods in some cases, even when no -0 exists as one of the parameters. E.g., using Math.pow to raise -Infinity to the power of any negative, odd exponent evaluates to -0. Refer to the documentation for the individual methods.
    It's possible to get a -0 return value out of these methods in some cases where a -0 exists as one of the parameters. E.g., Math.min(-0, +0) evalutes to -0. Refer to the documentation for the individual methods.
    Each of these operators uses the ToInt32 algorithm internally. Since there is only one representation for 0 in the internal 32-bit integer type, -0 will not survive a round trip after an inverse operation. E.g., both, -0) and << 2 >> 2, -0) evaluate to false.

    Relying on when the signedness of zeroes is not taken into account can be hazardous. Of course, when the intent is to distinguish between -0 and +0, it does exactly what's desired.


    此页面的贡献者有: jpuncle, Breezewish, teoli
    最后编辑者: Breezewish,