В чем разница между (NaN!= NaN) и (NaN!= NaN)?
Прежде всего, хочу отметить, что я знаю, как работают isNaN()
и Number.isNaN()
. Я читаю "Определенное руководство" Дэвида Фланагана, и он приводит пример того, как проверить, имеет ли значение NaN
:
x !== x
Это приведет к true
тогда и только тогда, когда x
будет NaN
.
Но теперь у меня есть вопрос: почему он использует строгое сравнение? Потому что кажется, что
x != x
ведет себя одинаково. Безопасно ли использовать обе версии или я пропускаю некоторые значения в JavaScript, которые возвратят true
для x !== x
и false
для x != x
?
Ответы
Ответ 1
Во-первых, позвольте мне заметить, что NaN
- очень специальное значение: по определению оно не равно самому себе. Это исходит из стандарта IEEE-754, на который нарисованы номера JavaScript. Значение "не число" никогда не совпадает с самим собой, даже если бит является точным совпадением. (Что они не обязательно в IEEE-754, это позволяет использовать несколько разных значений "не число".) Вот почему это даже появляется; все остальные значения в JavaScript равны самим себе, NaN
является только специальным.
... Я пропустил какое-то значение в JavaScript, которое вернет true для x! == x и false для x!= x?
Нет, это не так. Единственное различие между !==
и !=
заключается в том, что последний будет прибегать к типу принуждения, если необходимо, чтобы типы операндов были одинаковыми. В x != x
типы операндов одинаковы, поэтому они точно такие же, как x !== x
.
Это ясно из начала определения Abstract Equality Operation:
- ReturnIfAbrupt (х).
- ReturnIfAbrupt (у).
-
Если тип (x) совпадает с типом (y), то
Возвращает результат выполнения строгого сравнения равенств x === y.
-
...
Первые два шага - это базовая сантехника. Таким образом, самый первый шаг ==
заключается в том, чтобы увидеть, являются ли типы одинаковыми и, если да, сделать ===
. !=
и !==
являются просто отрицательными версиями этого.
Итак, если Flanagan верен, что только NaN
выдаст true для x !== x
, мы можем быть уверены, что оно также верно, что только NaN
выдаст true для x != x
.
Многие программисты JavaScript по умолчанию используют ===
и !==
, чтобы избежать некоторых ловушек вокруг тикового принуждения, которые выполняют свободные операторы, но в этом случае нет ничего, что можно было бы использовать в использовании Flanagan для строгого и свободного оператора.
Ответ 2
Для целей NaN, !=
и !==
делают то же самое.
Однако многие программисты избегают ==
или !=
в JavaScript. Например, Дуглас Крокфорд считает их среди "плохих частей" языка JavaScript, потому что они ведут себя непредсказуемыми и запутанными способами:
В JavaScript есть два набора операторов равенства: ===
и !==
, а их злые близнецы ==
и !=
. Хорошие работают так, как вы ожидали.
... Мой совет - никогда не использовать злых близнецов. Вместо этого всегда используйте ===
и !==
.
Ответ 3
Просто для удовольствия, позвольте мне показать вам искусственный пример, где x
не NaN
, но в любом случае операторы ведут себя по-другому. Сначала определите:
Object.defineProperty(
self,
'x',
{ get: function() { return self.y = self.y ? 0 : '0'; } }
);
Тогда имеем
x != x // false
но
x !== x // true
Ответ 4
Я просто хочу указать, что NaN
- это не единственная вещь, которая производит x !== x
без использования глобального объекта. Существует множество умных способов вызвать это поведение. Здесь используется метод getters:
var i = 0, obj = { get x() { return i++; }};
with(obj) // force dynamic context, this is evil.
console.log(x === x); // false
Как отмечают другие ответы, ==
выполняет операции с типом, но как в других языках, так и в стандарте - NaN указывает на сбой вычисления и по уважительным причинам не равен самому себе.
По какой-то причине люди не рассматривают эту проблему с JS, но большинство языков, которые имеют удвоение (а именно C, Java, С++, С#, Python и др.), демонстрируют это точное поведение, и люди в порядке с ним.
Ответ 5
Как иногда изображения лучше, чем слова, проверьте table (вот почему я должен сделать этот ответ вместо комментарий потому, что он становится лучше видимым).
Там вы можете видеть, что строгое сравнение равенства (===) возвращает true только в том случае, если тип и контент совпадают, поэтому
var f = "-1" === -1; //false
В то время как абстрактное сравнение равенства (==) проверяет только содержимое * путем преобразования типов, а затем строго их сравнивает:
var t = "-1" == -1; //true
Хотя это неясно, не советуя ECMA, что JavaScript рассматривает при сравнении, таким образом, что приведенный ниже код оценивается как true.
var howAmISupposedToKnowThat = [] == false; //true