JavaScript的相等性传递性很奇怪

43
我一直在阅读道格拉斯·克罗克福德(Douglas Crockford)的JavaScript: The Good Parts,然后我遇到了这个奇怪的例子,它对我来说毫无意义:
'' == '0'           // false
0 == ''             // true
0 == '0'            // true

false == undefined  // false
false == null       // false
null == undefined   // true

作者还提到“永远不要使用 == != 。相反,总是使用 === !== ”。然而,他没有解释为什么会出现上述行为?所以我的问题是,为什么会出现上述结果?JavaScript中是否考虑传递性?

2
回答这个问题的最好方法是阅读规范:http://www.ecma-international.org/publications/standards/Ecma-262.htm 如果你真的想知道为什么上面的语句是这样的,那么没有比这更好的方法了。准备好在某些地方费点力气,但如果你像这样提出问题,那么付出的努力是值得的。 - T.J. Crowder
5
应该指出的是,涉及“false”、“undefined”和“null”的第二组相等性不违反传递性 - 它与“A!= B,A!= C,B == C”相同。 - Nacht
请查看第三级别:http://alf.nu/ReturnTrue - JohnLBevan
另一个例子是 false==''false==' ',但是 ''!=' '。换句话说,空字符串和只有一个空格的字符串都是false(假),但不相等。 - user3546284
我非常同意这一点 - JavaScript 的等式传递性很奇怪。 - RBT
显示剩余2条评论
3个回答

35
'' == '0' // false

左侧是一个空字符串,右侧是一个包含一个字符的字符串。它们是错误的,因为它在两个不同的字符串之间进行比较(感谢Niall)。
0 == '' // true

因此,这个表达式是正确的,因为0和空字符串都是falsy
0 == '0' // true

这个有点棘手。规范说明如果操作数是字符串和数字,则将字符串强制转换为数字。'0' 变成了 0。感谢 smfoote

false == undefined // false

JavaScript中,值undefined是特殊的,除了null之外不等于任何其他值。然而,它是falsy的。
false == null // false

再次强调,null 是特殊的。它只等于 undefined。它也是 falsy

null == undefined // true

nullundefined很相似,但并不完全一样。null表示空值,而undefined是一个变量未设置或不存在的值。它们的值被认为是相等的可能有点合理。

如果你想更加混淆,请看这个...

'\n\r\t' == 0

只由空格组成的字符串被视为等于0。

Douglas Crockford提出了很多建议,但您不必将它们视为教义。 :)

T.J. Crowder提出了一个很好的建议,即研究ECMAScript语言规范以了解这些相等性测试背后的整个故事。

进一步阅读?

规范

yolpo(关于假值)


3
“Douglas Crockford提出了很多建议,但你不必把它们视为圣经。”说得好。Crockford是一个聪明的人,他对语言的目的进行了深思熟虑,因此阅读他提出的观点和论据非常值得。然后自己得出结论。 - T.J. Crowder
@alex... 在你第三段开头说的“这个有点棘手”的地方,你是不是指 == 会检查类型? - Hristo
@Niall 你说得完全正确,我也不知道为什么我写了那个:P 我会进行编辑。 - alex
你对 0 == '' 为什么成立的解释也是不正确的。在进行字符串和数字的非严格相等比较时,ECMAScript 总是将字符串强制转换为数字。 - smfoote
@smfoote 很好的发现,我在回答之前应该更多地参考规范。 - alex
显示剩余4条评论

8
这个问题的答案与JavaScript如何处理强制类型转换有关。在 == 的情况下,字符串被强制转换为数字。因此: '' == '0'等同于'' === '0'(两者都是字符串,因此不需要强制类型转换)。 0 == ''等同于0 === 0,因为字符串''变成了数字0math.abs('') === 0)。 0 == '0'由于同样的原因,等同于0 === 0false == undefined等同于0 === undefined,因为当类型不匹配时,JavaScript会将布尔值强制转换为数字。 false == null由于同样的原因,等同于0 === nullnull == undefined是true,因为规范是这样规定的。
感谢您提出这个问题。通过研究它,我对 == 的理解更加深入了。

4

你可以编写一个 JavaScript 函数,它的行为与 == 完全相同,这将帮助你更好地理解其行为。

下面是该函数的代码:

// loseEqual() behaves just like `==`
function loseEqual(x, y) {
    // notice the function only uses "strict" operators 
    // like `===` and `!==` to do comparisons

    if(typeof y === typeof x) return y === x;

    if(typeof y === "function" || typeof x === "function") return false;

    // treat null and undefined the same
    var xIsNothing = (y === undefined) || (y === null);
    var yIsNothing = (x === undefined) || (x === null);

    if(xIsNothing || yIsNothing) return (xIsNothing && yIsNothing);

    if(typeof x === "object") x = toPrimitive(x);
    if(typeof y === "object") y = toPrimitive(y);

    if(typeof y === typeof x) return y === x;

    // convert x and y into numbers if they are not already use the "+" trick
    if(typeof x !== "number") x = +x;
    if(typeof y !== "number") y = +y;

    return x === y;
}

function toPrimitive(obj) {
    var value = obj.valueOf();
    if(obj !== value) return value;
    return obj.toString();
}

正如您所看到的==存在大量的复杂逻辑来进行类型转换。因此很难预测你会得到什么结果。

这里有一些例子,它们的结果可能让您感到意外:

意外的真相

[1] == true // returns true
'0' == false // returns true
[] == false // returns true
[[]] == false // returns true
[0] == false // returns true

'\r\n\t' == 0 // returns true

意外的结论

// IF an empty string '' is equal to the number zero (0)
'' == 0 // return true

// AND the string zero '0' is equal to the number zero (0)
'0' == 0 // return true

// THEN an empty string must be equal to the string zero '0'
'' == '0' // returns **FALSE**

特殊功能对象


// Below are examples of objects that
// implement `valueOf()` and `toString()`

var objTest = {
    toString: function() {
        return "test";
    }
};

var obj100 = {
    valueOf: function() {
        return 100;
    }
};

var objTest100 = {
    toString: function() {
        return "test";
    },
    valueOf: function() {
        return 100;
    }
};

objTest == "test" // returns true
obj100 == 100 // returns true
objTest100 == 100 // returns true

objTest100 == "test" // returns **FALSE**

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接