Транзитивность равенства 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
Причина в том, что идентификатор или строгий оператор (===), он сравнивается без преобразования типа, это означает, что если оба значения не имеют одинакового значения и одного и того же типа, они не будут считаться равными.
взгляните на эту ссылку, вы не сомневаетесь:
простой способ понять, как работает оператор идентификации