Транзитивность равенства JavaScript странная

Я читал Дуглас Крокфорд JavaScript: Хорошие Части, и я наткнулся на этот странный пример, который не имеет смысла для меня:

'' == '0'           // false
0 == ''             // true
0 == '0'            // true

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

автор также продолжает упоминать "никогда не использовать == и !=. Вместо этого, всегда используйте === и !==". Однако он не объясняет, почему такое поведение проявляется? Поэтому мой вопрос: почему вышеуказанные результаты таковы, каковы они есть? Не рассматривается ли транзитивность в В JavaScript?

4 ответов


'' == '0' // false

левая сторона-пустая строка, а правая сторона-строка с одним символом. Они ложны, потому что он делает сравнение между двумя не идентичными строками (спасибо Найл).

0 == '' // true

значит, почему это верно, потому что 0 is ложь и пустая строка ложь.

0 == '0' // true

это немного сложнее. Спецификация утверждает, что если операнды являются строкой и number, затем принудите строку к number. '0' становится 0. Спасибо smfoote.

false == undefined // false

значение undefined является специальным В JavaScript и не равен ничему, кроме null. Однако, это ложь.

false == null // false

опять null особенная. Он равен только undefined. Это также ложь.

null == undefined // true

null и undefined похожи, но не одинаковы. null означает ничего, а undefined - значение переменной, не заданное или не существующее. Было бы разумно, чтобы их ценности считались равными.

если вы хотите быть действительно перепутал, проверь это...

'\n\r\t' == 0

строка, состоящая только из пробелов, считается равной 0.

Дуглас Крокфорд дает много рекомендаций, но вы не должны принимать их как Евангелие. :)

Ти Джей Краудер делает отличное предложение по изучению Спецификация Языка ECMAScript чтобы узнать всю историю этих тестов на равенство.

Дальше Читать?

спец.

yolpo (о ложных значениях)


ответ на этот вопрос связан с тем, как JavaScript обрабатывает принуждения. В случае ==, строки принуждаются быть числами. Таким образом:

'' == '0' эквивалентно '' === '0' (оба являются строками, поэтому принуждение не требуется).

0 == '' эквивалентно 0 === 0 потому что строка '' становится номером 0 (math.abs('') === 0).

0 == '0' эквивалентно 0 === 0 для того же причина.

false == undefined эквивалентно 0 === undefined потому что JavaScript заставляет логические значения быть числами, когда типы не совпадают

false == null эквивалентно 0 === null по той же причине.

null == undefined верно, потому что спецификация так говорит.

Спасибо, что задали этот вопрос. Мое понимание == гораздо лучше изучив его.


вы можете написать функцию 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();
}

Как видите,== много сложной логики для преобразования типов. Из-за этого трудно предсказать, какой результат вы получите.

вот несколько примеров некоторых результатов, которые вы не ожидали бы:

неожиданный Истины!--16-->

[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**

причина в том, что identity или strict operator ( = = = ), он сравнивается без преобразования типов, что означает, что если оба значения не имеют одного и того же значения и одного типа, они не будут считаться равными.

взгляните на эту ссылку, она выводит вас из сомнений: простой способ понять, как работает оператор идентификации