Заметки с тегом
Javascript
Различия операторов == и === в JavaScript

Каждый раз я с опаской заменяю == на === — боюсь сломать логическое выражение. Ведь оператор равенства == реализует много неявной логики по сравнению значений, чем мог воспользоваться предыдущий разработчик.

Операторы == и === проверяют значения на совпадение, используя различные определения совпадения. Оператор идентичности (identity) === проверяет операнды на «идентичность», руководствуясь строгим определением совпадения. Оператор равенства (equality) == проверяет по менее строгим правилам, допускающим преобразования типов.

Оператор идентичности === вычисляет значения своих операндов, а затем сравнивает, без преобразования типов. Он руководствуется правилами:

  • Если у значений разные типы — они не идентичны.
  • Если оба значения или null или undefined — они идентичны.
  • Если оба значения или true или false — они идентичны.
  • Если одно или оба значения — NaN — они не идентичны. (Значение NaN никогда не идентично никакому значению, даже самому себе. Чтобы проверить значение x на NaN, используйте выражение x !== x. Только для NaN такая проверка вернет true).
  • Если оба операнда это числа с одним и тем же значением — они идентичны. Если одно число равно 0, а другое -0, они также идентичны.
  • Если оба значения это строки и содержат одни и те же 16-битные значения в одинаковых позициях — они идентичны. Две строки могут иметь один и тот же смысл и одинаково выглядеть на экране, но содержать отличающиеся последовательности 16-битных значений. Интерпретатор JavaScript не выполняет нормализацию символов юникода, поэтому подобные пары строк не считаются операторами === и == ни равными, ни идентичными.
  • Если оба значения ссылаются на один и тот же объект, массив или функцию — они идентичны. Если они ссылаются на различные объекты — они не идентичны, даже при идентичных свойствах.

Оператор равенства == похож на оператор идентичности, но он использует менее строгие правила. Если у значений разные типы — они преобразуются и сравниваются:

  • Если у значений одинаковый тип, они проверяются на идентичность, как описано выше.
  • Если значения не относятся к одному типу, оператор == считает их равными, при следующих правилах:
    • Если одно значение null, а другое undefined — они равны.
    • Если одно значение число, а другое строка, то строка преобразуется в число и выполняется сравнение.
    • Если одно значение — true, оно перед сравнением преобразуется в 1. Если — false, оно преобразуется в 0 и сравнение выполняется снова.
    • Если одно значение число или строка, а другое — объект, то перед сравнением объект преобразуется в простой тип. Встроенные классы преобразуются методом valueOf(), если не получилось, то toString(). Класс Date всегда выполняет преобразование toString(). Не базовые объекты джаваскрипта сами определяют способ преобразования в простые типы.
    • Любые другие комбинации значений не равны.

Правила преобразования типов и сравнения значений для оператора равенства == сложные и труднозапоминаемые. Интересные случаи:

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

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

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

' \t\r\n ' == 0     // true

Особый случай — сравнение литерал с объектом:

"abc" == new String("abc")    // true
"abc" === new String("abc")   // false

Здесь, оператор == проверяет значение объектов и возвращает true. Оператор === возвращает false, т.к. у объектов различные типы. Какое поведение корректно? Зависит от того, что сравнивать. Но лучше обойти вопрос, и не использовать конструктор для создания строковых объектов.

В заключении — таблицы сравнения значений для операторов равенства и идентичности с сайта dorey.github.io.

Для оператора == (или !=):

Таблица сравнения значений для оператора ==

Для оператора === (или !==):

Таблица сравнения значений для оператора ==

Из таблиц следует вывод, что поведение == не очевидно и может только запутать. Используя === можно быть уверенным в возвращаемом значении.

Интересная статья: When is it OK to use == in JavaScript?