Неявное преобразование типа данных в JavaScript при сравнении целого с строкой с использованием ==
Код:
var num = 20;
if(num == "20")
{
alert("It works");
}
else
{
alert("Not working");
}
Вопрос:
-
В программировании на языке С у нас есть продвижение типа данных типа имени правила, где, когда существует смешанный тип данных (пример: добавление целого числа и с плавающей запятой), целое число сначала преобразуется в плавающую точку до того, как добавление будет выполнить.
-
Приведенный выше код подскажет мне окно с сообщением "It works"
, которое показывает, что условие проверки if
равно true.
-
Для слабо типизированного JavaScript мне просто интересно: существует ли какое-либо правило, такое как C, которое определяет, какое преобразование будет выполняться в какой ситуации? Кроме того, приведенный выше код JavaScript преобразует значение переменной num
из целочисленного значения в строковое значение перед выполнением сравнения или наоборот?
Ответы
Ответ 1
Да, все правила преобразования типов, применяемые оператором equals, описаны в спецификации ECMA-262 в Алгоритм сравнения абстрактного равенства.
Алгоритм может выглядеть довольно сложным, но его можно обобщить на следующие случаи:
-
Тип двух операндов одинаковый:
- Для примитивов (String, Number, Boolean, Null, Undefined)
- Возвращает true, если значение точно такое же
- Для типа объекта
- Возвращает true, если две ссылки указывают на один и тот же объект
-
Если типы двух операндов отличаются
- Если тип одного операнда имеет значение Null или Undefined
- Возвращает true, только если другое значение операнда равно
null
или undefined
- Если один из операндов имеет тип Boolean или Number
- (после некоторых шагов) Преобразуйте другой операнд в число и сравните
-
Если один из операндов - это Object, а другой - примитив
- Выполните преобразование объектов в примитив в объект и сравните его снова
Преобразование Object-to-Primitive выполняется с помощью абстрактной операции ToPrimitive
, этот метод попытается преобразовать объект в примитивное значение, используя внутренний метод [[PrimitiveValue]]
.
Это попытается выполнить эжектирование методов valueOf
и toString
, и оно примет значение первого, возвращающее примитивное значение.
В случае, если эти два метода не возвращают примитив, или они не подлежат вызову, генерируется TypeError
, например:
1 == { toString:null } // TypeError!
Вышеприведенный оператор создает TypeError
, потому что метод по умолчанию Object.prototype.valueOf
не делает ничего больше, чем фактически тот же экземпляр объекта (this
, а не примитивное значение), и мы устанавливаем собственный toString
свойство, которое не является функцией.
Друг сделал небольшой инструмент, который может быть вам интересен, он показывает все этапы и рекурсивные сравнения между типами:
Ответ 2
В JavaScript есть два оператора, которые могут использоваться для сравнения двух значений: операторы ==
и ===
.
Цитируется из JavaScript Полное руководство 6-го издания:
Оператор равенства ==
подобен строгому оператору равенства (===
), но он менее строг. Если значения двух операндов не совпадают, он пытается преобразовать некоторые типы и снова пытается провести сравнение.
и
Строгий оператор равенства ===
оценивает свои операнды, а затем сравнивает два значения, как показано ниже, без преобразования типа.
Поэтому я предлагаю вам использовать ===
все время, чтобы избежать таких проблем, как:
null == undefined // These two values are treated as equal.
"0" == 0 // String converts to a number before comparing.
0 == false // Boolean converts to number before comparing.
"0" == false // Both operands convert to numbers before comparing.
P.S. Я мог бы опубликовать все "сравнительные рекомендации", как написано в книге, но слишком долго;) Просто скажите мне, и я отредактирую свой пост для вас.
Ответ 3
Избегайте неявного преобразования типов в JavaScript. Всегда выполняйте шаги для тестирования и/или преобразования отдельных значений перед их сравнением, чтобы убедиться, что вы сравниваете яблоки с яблоками. Всегда проверяйте явно для undefined, чтобы определить, имеет ли значение или свойство значение, используйте значение null, чтобы указать, что переменные или свойства объекта не относятся к какому-либо объекту, а также преобразовывать и сравнивать все другие значения, чтобы гарантировать выполнение операций с значениями тот же тип.
Ответ 4
Я знаю, на вопрос был дан ответ. То, что я привел ниже, является примером нескольких преобразований. Это будет полезно для тех, кто не знаком с JavaScript. Вышеуказанный результат можно сравнить с общим алгоритмом для легкого понимания.
Код:
var values = ["123",
undefined,
"not a number",
"123.45",
"1234 error",
"",
" ",
null,
undefined,
true,
false,
"true",
"false"
];
for (var i = 0; i < values.length; i++){
var x = values[i];
console.log("Start");
console.log(x);
console.log(" Number(x) = " + Number(x));
console.log(" parseInt(x, 10) = " + parseInt(x, 10));
console.log(" parseFloat(x) = " + parseFloat(x));
console.log(" +x = " + +x);
console.log(" !!x = " + !!x);
console.log("End");
}
Выход:
"Start"
"123"
" Number(x) = 123"
" parseInt(x, 10) = 123"
" parseFloat(x) = 123"
" +x = 123"
" !!x = true"
"End"
"Start"
undefined
" Number(x) = NaN"
" parseInt(x, 10) = NaN"
" parseFloat(x) = NaN"
" +x = NaN"
" !!x = false"
"End"
"Start"
"not a number"
" Number(x) = NaN"
" parseInt(x, 10) = NaN"
" parseFloat(x) = NaN"
" +x = NaN"
" !!x = true"
"End"
"Start"
"123.45"
" Number(x) = 123.45"
" parseInt(x, 10) = 123"
" parseFloat(x) = 123.45"
" +x = 123.45"
" !!x = true"
"End"
"Start"
"1234 error"
" Number(x) = NaN"
" parseInt(x, 10) = 1234"
" parseFloat(x) = 1234"
" +x = NaN"
" !!x = true"
"End"
"Start"
""
" Number(x) = 0"
" parseInt(x, 10) = NaN"
" parseFloat(x) = NaN"
" +x = 0"
" !!x = false"
"End"
"Start"
" "
" Number(x) = 0"
" parseInt(x, 10) = NaN"
" parseFloat(x) = NaN"
" +x = 0"
" !!x = true"
"End"
"Start"
null
" Number(x) = 0"
" parseInt(x, 10) = NaN"
" parseFloat(x) = NaN"
" +x = 0"
" !!x = false"
"End"
"Start"
undefined
" Number(x) = NaN"
" parseInt(x, 10) = NaN"
" parseFloat(x) = NaN"
" +x = NaN"
" !!x = false"
"End"
"Start"
true
" Number(x) = 1"
" parseInt(x, 10) = NaN"
" parseFloat(x) = NaN"
" +x = 1"
" !!x = true"
"End"
"Start"
false
" Number(x) = 0"
" parseInt(x, 10) = NaN"
" parseFloat(x) = NaN"
" +x = 0"
" !!x = false"
"End"
"Start"
"true"
" Number(x) = NaN"
" parseInt(x, 10) = NaN"
" parseFloat(x) = NaN"
" +x = NaN"
" !!x = true"
"End"
"Start"
"false"
" Number(x) = NaN"
" parseInt(x, 10) = NaN"
" parseFloat(x) = NaN"
" +x = NaN"
" !!x = true"
"End"
Ответ 5
Лучше использовать код ниже для понимания неявного преобразования.
var values = [ 0 , 123, "0", "123", -0, +0, NaN, +NaN, -NaN, false, true, "false", "true", null, undefined, "null", "undefined", "", "GoodString", " "];
for (var i = 0; i < values.length; i++){
console.log("<<<<<<<<<<<<Starting comparing: " + i + ">>>>>>>>>>>>>>>");
for (var j = 0; j < values.length; j++){
console.log(values[i],`==`, values[j]);
console.log(eval(values[i] == values[j]));
}
}