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

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

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

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

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

Ответ 1

'' == '0' // false

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

0 == '' // true

Следовательно, почему это истинно, потому что 0 является ложным, а пустая строка - фальшивой.

0 == '0' // true

Это немного сложнее. Спецификация утверждает, что если операнды являются строкой и числом, то принуждение строки к номеру. '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.

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

T.J. Crowder дает отличное предложение изучить Спецификацию ECMAScript Language, чтобы узнать всю историю этих тестов равенства.

Дальнейшее чтение?

Спецификация.

yolpo (по значениям ложности)

Ответ 2

Ответ на этот вопрос связан с тем, как 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 истинно, потому что спецификация говорит так.

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

Ответ 3

Фактически вы можете написать функцию 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**

Ответ 4

Причина в том, что идентификатор или строгий оператор (===), он сравнивается без преобразования типа, это означает, что если оба значения не имеют одинакового значения и одного и того же типа, они не будут считаться равными.

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