Сравнение двойного равенства в 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 говорит:
Когда вы передаете строку в Number (), этот метод не может преобразовать данное значение в число и возвращает NaN. .
Это означает Не число и не равно 0.
0 == NaN // false
Мы можем создавать забавные вещи для этого, теперь все Объекты равны «да», но это что-то сломает 😅.
Object.prototype.valueOf = function () { return "yey" } "yey" == {} // true
Вы увидите более сложные и абсурдные мемы. Javascript - язык со слабой типизацией. Это означает, что каждое сравнение автоматически выполняется движками с алгоритмами, но предлагает такие элементы управления, как === равенство. Если вы видите сложный случай, подобный предыдущим примерам, официальные документы, такие как ECMAScript и MDN, могут объяснить все, и они могут помочь понять, как работать с Javascript.