Прежде всего хочу отметить, что я знаю, как isNaN() и Number.isNaN() работают. Я читаю Определенное руководство Дэвида Фланагана, и он приводит пример того, как проверить, является ли значение NaN:

x !== x

Это приведет к true тогда и только тогда, когда x равен NaN.

Но теперь у меня вопрос: почему он использует строгое сравнение? Потому что кажется, что

x != x

Ведет себя так же. Безопасно ли использовать обе версии, или мне не хватает некоторых значений в JavaScript, которые будут возвращать true для x !== x и false для x != x?

149
Giorgi Nakeuri 14 Дек 2015 в 10:44

5 ответов

Лучший ответ

Во-первых, позвольте мне указать, что NaN - это особенное значение: по определению оно не равно самому себе. Это происходит из стандарта IEEE-754, на котором основаны числа JavaScript. Значение «не число» никогда не равно само себе, даже если биты точно совпадают. (В IEEE-754 они не обязательно, он допускает несколько разных значений «не число».) Вот почему это даже подходит; все остальные значения в JavaScript равны себе, NaN просто особенный.

... мне не хватает некоторого значения в JavaScript, которое будет возвращать true для x! == x и false для x! = x?

Нет, ты не Единственная разница между !== и != заключается в том, что последний будет выполнять приведение типов, если необходимо, чтобы типы операндов были одинаковыми. В x != x типы операндов совпадают, и поэтому они точно такие же, как x !== x.

Это ясно с самого начала определения Операция абстрактного равенства:

    < Литий> ReturnIfAbrupt ( х) . < Литий> ReturnIfAbrupt ( у) .
  1. Если тип (x) совпадает с типом (y), то

    Вернуть результат выполнения сравнения строгого равенства x === y.

  2. < Li> < p> ...

Первые два шага - это базовая сантехника. Таким образом, по сути, самый первый шаг == состоит в том, чтобы увидеть, совпадают ли типы, и, если да, сделать === вместо этого. != и !== являются просто отрицательными версиями этого.

Поэтому, если Фланаган прав, что только NaN даст истину для x !== x, мы можем быть уверены, что также верно, что только NaN даст истину для x != x.

Многие программисты JavaScript по умолчанию используют === и !==, чтобы избежать некоторых ловушек вокруг приведения типов, которые делают свободные операторы, но в этом случае нечего читать при использовании Фланаганом оператора строгого и свободного.

128
T.J. Crowder 25 Мар 2016 в 17:21

Для целей NaN != и !== делают то же самое.

Однако многие программисты избегают использования == или != в JavaScript. Например, Дуглас Крокфорд считает их среди "плохих частей "языка JavaScript, потому что они ведут себя неожиданным и запутанным образом:

В JavaScript есть два набора операторов равенства: === и !==, а также их злые близнецы == и !=. Хорошие работают так, как вы ожидаете.

... Мой совет - никогда не использовать злых близнецов. Вместо этого всегда используйте === и !==.

37
Willem Van Onsem 15 Дек 2015 в 12:37

Я просто хочу отметить, что NaN - не единственное, что создает x !== x без использования глобального объекта. Есть много умных способов вызвать это поведение. Вот один, использующий геттеры:

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, C ++, C #, Python и другие) демонстрируют это точное поведение, и люди просто в порядке.

2
Benjamin Gruenbaum 15 Дек 2015 в 08:49

Просто для удовольствия, позвольте мне показать вам искусственный пример, где x не NaN, но операторы ведут себя по-разному. Сначала определите:

Object.defineProperty(
  self,
  'x',
  { get: function() { return self.y = self.y ? 0 : '0'; } }
);

Тогда у нас есть

x != x // false

Но

x !== x // true
22
GOTO 0 14 Дек 2015 в 11:19

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

Там вы можете увидеть, что строгое сравнение равенства (===) возвращает true только если тип и содержимое совпадают, поэтому

var f = "-1" === -1; //false

В то время как сравнение абстрактного равенства (==) проверяет только содержимое *, преобразовывая типы и затем строго сравнивая их:

var t = "-1" == -1; //true

Хотя это не ясно, без консультации с ECMA, что учитывает JavaScript при сравнении, так как код ниже оценивает как true.

 var howAmISupposedToKnowThat = [] == false; //true
0
MVCDS 16 Дек 2015 в 11:17