JavaScript транзитивность равенства странно - PullRequest
37 голосов
/ 27 марта 2011

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

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

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

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

Ответы [ 4 ]

30 голосов
/ 27 марта 2011
'' == '0' // false

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

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 , чтобы узнать всю историю этих тестов на равенство.

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

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

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

8 голосов
/ 27 февраля 2014

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

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

4 голосов
/ 09 августа 2016

На самом деле вы можете написать функцию 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**
0 голосов
/ 22 октября 2015

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

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

...