Рассказ о преобразовании типов
Когда дело доходит до оператора равенства, бывает сложно понять, как JavaScript обрабатывает преобразование типов. Лучшее понимание - или, по крайней мере, наличие ссылки, к которой можно вернуться - может положительно повлиять на ваше кодирование и лучше подготовить вас к загадкам и непреднамеренным побочным эффектам преобразования типов.
Мы надеемся, что эта статья станет тем справочником как для вас, так и для меня. Начнем с определений!
Строгое равенство
Строгое равенство (===
, часто ==
на других языках) знакомо большинству программистов. Он проверяет, идентичны ли два значения и одного и того же типа.
Операнд
Объект / значение, которое мы используем в операции. В 5 == '5'
есть два операнда - 5
и '5'
.
Преобразование типов
Преобразование типов - это перенос данных из одного типа данных в другой. Это может происходить неявно (когда компилятор автоматически назначает типы данных) или явно (когда ваш код сообщает JavaScript, что нужно выполнить преобразование). Когда преобразование происходит автоматически, как в случае с оператором равенства, мы также называем этот процесс приведением типов. Давайте посмотрим на это в действии.
Оператор равенства
Оператор равенства (==
) выполняет преобразование типов при сравнении операндов. Это может быть полезно при сравнении значений, которые выглядят одинаково, но относятся к разным типам.
Одним из таких случаев является проверка чисел по строкам, которые выглядят как числа.
5 == '5'; // true
Отчасти понятно, что здесь происходит. Строка конвертируется в число, затем проверяется строгое равенство… верно? Может быть! Может, число переводится в строку? В этом посте я приведу конкретные примеры и описание вопросов, связанных с преобразованием типов.
Спецификация ECMAScript может сбивать с толку. Он почти читается как исследовательская работа по математике. Когда я хотел получить более подробную информацию об операторе равенства, я обратился к источнику. Ниже я построю простой протокол, который поможет вам определить, как абстрактное равенство работает в нескольких сценариях.
ЗАМЕТКА:
Некоторые шаги будут иметь явный возврат (например, # 2):
-return true
Другие вместо этого будут выводить новую операцию абстрактного равенства (например, # 3):
-5 == 5;
Результирующие операнды возвращаются на шаг № 1, где алгоритм повторяется до тех пор, пока не будет достигнут явный возврат.
Абстрактный алгоритм сравнения равенства
Обновлено для ECMA2020.
For x == y,
выполните следующие действия:
1. Если x
и y
относятся к одному и тому же типу , верните x === y
5 === 5; => true
'foo' === 'bar'; => false
false === false; => true
null === undefined; => false
{ foo: 'bar' } === { foo: 'bar' }; => false
2. Если x
равно null
, а y
равно undefined
(или наоборот), вернуть true
null == undefined; => true
3. Если x
- строка, а y
- число (или наоборот), преобразовать строку в число
'5' == 5;
=> convert '5' to Number
=> Number('5') => 5
5 == 5;
4. Если x
- это BigInt, а y
- это строка (или наоборот), преобразуйте строку в BigInt
BigInt(5) == '5'; => convert '5' to BigInt => Bigint('5')
BigInt(5) == BigInt('5');
5. Если x
или y
является логическим, преобразуйте его в число
true == 3; => convert true to Number => Number(true) => 1
1 == 3;
false == 'foo'; => convert false to Number => Number(false) => 0
0 == 'foo';
6. Если x
является строкой, числом, BigInt или символом, а y
является объектом (или наоборот), попытайтесь преобразовать объект в примитив.
Иногда объекты имеют встроенные / предопределенные методы, которые помогают с преобразованием в примитивы. Такие методы выходят за рамки этой статьи, и мы проигнорируем эти частные случаи - мы будем использовать простой объект { foo: 'bar' }
для этого шага.
’baz’ == { foo: 'bar' }; 5 == { foo: 'bar' }; BigInt(5) == { foo: 'bar' }; Symbol('baz') == { foo: 'bar' };
В каждом из этих случаев для преобразования используется toString
метод объекта. По умолчанию этот метод просто возвращает строку '[object Object]'
.
[String/Number/BigInt/Symbol] == { foo: 'bar' }; => convert object using .toString() => { foo: 'bar' }.toString() => '[object Object]' [String/Number/BigInt/Symbol] == '[object Object]';
7. Если x
является BigInt, а y
- числом (или наоборот):
- Если
x
илиy
равноNaN
,+∞
или-∞
, вернутьfalse
BigInt(5) == NaN; => false BigInt(5) == Infinity; => false BigInt(5) == -Infinity; => false
- Если ни
x
, ниy
не равноNaN
,+∞
или-∞
, заполните Строгое равенство для математических значенийx
иy
BigInt(5) == 5; => Number(BigInt(5)) => 5 5 === 5; => true BigInt(5) == 3; => Number(BigInt(5)) => 5 5 === 3; => false
8. Если вы дойдете до конца этого контрольного списка, верните false
Наконец, мы можем дать окончательный ответ на наш первоначальный вопрос!
5 == '5'; => Step #3 => If x is a String and y is a Number (or vice-versa), => convert the String to a Number Number('5') => 5 // return to top of protocol 5 == 5; => Step #1 => If x and y are of the same type, return x === y 5 === 5; => true
Теперь мы подтвердили, что в этом примере наша строка '5'
преобразована в число, затем было проверено строгое равенство с использованием результата.
Заключение
Большой! Надеюсь, это руководство послужит полезным справочником для ваших нужд оператора равенства.
В JavaScript есть несколько других операторов, которые инициируют преобразование типов. В следующий раз я исследую их в другом пошаговом руководстве. Я хотел бы услышать ваш отзыв, поэтому оставьте, пожалуйста, отзыв! Это поможет мне в будущих статьях.