Сравнение двойного равенства в Javascript сильно отличается от других языков программирования из-за слабой типизации Javascript. Если вы долгое время работаете со строго типизированным языком, вам может быть трудно понять эту вещь. Javascript рассматривается как неконтролируемый и нестандартный. Многие мемы и проблемы с программированием в Интернете поддерживают это решение.

Давайте посмотрим на один из них:

Начнем с первого случая

0 == "0" // true

Если вы скажете что-то вроде этого:

В Javascript double equals проверяет только значения, а не типы.

Да, вы правы, но мы разберемся, как работает Javascript в этих случаях.

Этот код работает так:

0 == Number(“0”) // true

В этих ситуациях движки Javascript запускают этот алгоритм Abstract Equality Comparison Algorithm (классное название).

Когда вы используете ==, этот алгоритм работает шаг за шагом, пока не будет найден результат.

Наш случай остановился на четвертом шаге. Это означает:

If Type(x) is Number and Type(y) is String,
return the result of the comparison x == ToNumber(y).

Когда наш случай отличается от этого:

0 == "1" // false

Результат будет ложным, поскольку преобразованное значение не равно «0».

Если вы хотите повеселиться, посмотрите это:

0 == “0000” // true
// Because Number(“0000”) returns 0

Продолжить со вторым случаем

0 == [] // true

Этот случай более сложный, чем предыдущий, потому что алгоритм запускается дважды.

Этот код работает так:

0 == Number([].valueOf().toString()) // true

В этом случае мы встретили примитивные типы. Алгоритм остановил наш случай на восьмом шаге. Это означает:

8. If Type(x) is either String or Number and Type(y) is Object,
return the result of the comparison x == ToPrimitive(y).

Он запускается снова, и наш случай остановлен на четвертом шаге, это означает:

4. If Type(x) is Number and Type(y) is String,
return the result of the comparison x == ToNumber(y).

Если вы отметите Abstract Equality Comparison Algorithm, вы увидите метод ToPrimitive (y) для сравнения объектов. Этот метод преобразует наш объект в примитивное значение. Мы не можем запустить вручную ToPrimitive (), потому что это собственный код, но мы можем изменить это поведение с помощью. valueOf (). Вам необходимо внимательно прочитать документ MDN, потому что важные примечания существуют следующим образом:

JavaScript автоматически вызывает его при обнаружении объекта, в котором ожидается примитивное значение.

Если мы не изменим .valueOf (), механизмы Javascript автоматически преобразуют примитивное значение по умолчанию. В следующем примечании объясняется, почему toString () вызывается после .valueOf ().

Объекты в строковом контексте преобразуются с помощью метода toString(), который отличается от преобразования объектов String в строковые примитивы с помощью valueOf. Все объекты имеют строковое преобразование, если только '[object type]'. Но многие объекты не преобразуются в числа, логические значения или функции.

Хорошо, это означает, что мы можем переопределить .valueOf () и вернуть наше значение. По сравнению с нашим объектом подход движка изменился.

Этот пример объясняет, что мы делаем:

Возможно ли, что переменная равна массиву, строке и числу? да.

Последний случай

"0" == [] // false

Этот код работает так:

0 == [].valueOf().toString()

Все выглядит так же, как и предыдущий, остановил наш случай на
восьмом шаге. Это означает:

8.If Type(x) is either String or Number and Type(y) is Object,
return the result of the comparison x == ToPrimitive(y).

Следующий шаг важен, потому что ToPrimitive () возвращает пустую строку для пустых массивов, и теперь наш код работает следующим образом:

"0" == ""

Алгоритм запускается снова и останавливает первый шаг:

If Type(x) is the same as Type(y), then
  d. If Type(x) is String, then return true if x and y are exactly   the same sequence of characters (same length and same characters in corresponding positions). Otherwise, return false.

ToPrimitive () преобразует наш массив в строку. Значит, наши типы сейчас такие же. Значения проверки алгоритма еще раз, тогда результат будет ложным, потому что «0» не равно «».

Бонус

Предыдущие примеры содержат массивы, а не Object. Когда мы пробуем те же случаи с объектами, кое-что может измениться.

0 == [] // true
0 == {} // false

Если вы спросите себя вот так:

Почему первый случай верен, а второй ложен?

Ответ настолько прост, этот код работает так:

0 == Number([].valueOf().toString()) // true
0 == Number(({}).valueOf().toString()) // false
({}).valueOf().toString() returns "[object Object]"
Number("[object Object]") returns NaN
NaN means "Not A Number" and not equal to 0
0 == NaN // false

Этот код может все изменить:

({}).valueOf().toString() // returns [object Object]

В этом случае MDN говорит:

Если этот метод не переопределен в настраиваемом объекте, toString() возвращает '[object type]', где type - тип объекта.

Когда вы передаете строку в Number (), этот метод не может преобразовать данное значение в число и возвращает NaN. .

Это означает Не число и не равно 0.

0 == NaN // false

Мы можем создавать забавные вещи для этого, теперь все Объекты равны «да», но это что-то сломает 😅.

Object.prototype.valueOf = function () {
 return "yey"
}
"yey" == {} // true

Вы увидите более сложные и абсурдные мемы. Javascript - язык со слабой типизацией. Это означает, что каждое сравнение автоматически выполняется движками с алгоритмами, но предлагает такие элементы управления, как === равенство. Если вы видите сложный случай, подобный предыдущим примерам, официальные документы, такие как ECMAScript и MDN, могут объяснить все, и они могут помочь понять, как работать с Javascript.