使用==比较整数和字符串时,JavaScript中的隐式数据类型转换

Implicit data type conversion in JavaScript when comparing integer with string using ==

本文关键字:数据 类型转换 JavaScript 整数 比较 字符串 使用      更新时间:2023-09-26

代码:

var num = 20;
if(num == "20")
{
    alert("It works");
}
else
{
    alert("Not working");
}

问题:

  1. 在C编程中,我们有一个名为数据类型提升的规则,当存在混合数据类型时(例如:整数和浮点数相加),在进行加法之前,整数将首先转换为浮点数。

  2. 上面的代码将提示我一个警告框,其中包含"It works"消息,显示if测试条件被评估为true。

  3. 对于松散类型的JavaScript,我只是好奇:是否有像C这样的规则决定在哪种情况下执行哪种转换?除此之外,上面的JavaScript代码转换num变量值从整数值到字符串值之前进行比较,反之亦然?

是的,所有由相等运算符应用的类型转换规则都在ECMA-262规范中描述,在抽象相等比较算法中。

这个算法可能看起来很复杂,但它可以概括为以下几种情况:

  1. 两个操作数的类型相同:

    • 对于原语(字符串,数字,布尔值,Null,未定义)
      • 如果值完全相同则返回true
    • 对象类型
      • 如果两个引用指向同一个对象返回true
  2. 如果两个操作数的类型不同

    • 如果一个操作数的类型为Null或Undefined
      • 仅当另一个操作数为nullundefined时返回true
    • 如果其中一个操作数是布尔类型或数字类型
      • (经过一些步骤)将另一个操作数转换为Number并比较
  3. 如果其中一个操作数是Object而另一个操作数是基元

    • 在对象上执行对象到原语的转换并再次比较

对象到原语的转换是通过一个叫做ToPrimitive的抽象操作完成的,这个方法将尝试使用内部的[[PrimitiveValue]]方法将对象转换为一个原语值。

这将尝试弹出对象的valueOftoString方法,它将取第一个返回原始值的方法的值。

如果这两个方法不返回原语,或者它们不可调用,则抛出TypeError,例如:

1 == { toString:null } // TypeError!

上面的语句将产生一个TypeError,因为默认的Object.prototype.valueOf方法除了实际相同的对象实例(this,不是原始值)之外没有做任何事情,并且我们正在设置一个自己的toString属性,它不是函数。

一个朋友做的小工具,你可能会感兴趣,它显示了所有的步骤和递归比较类型:

    JS强制转换工具

在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.

注:我可以把书中写的整个"比较指南"贴出来,但是太长了;)

避免JavaScript中的隐式类型转换。在比较它们之前,总是采取步骤来测试和/或转换单个值,以确保你是在逐个比较。始终显式地测试undefined以确定值或属性是否有值,使用null表示对象变量或属性不引用任何对象,并转换&比较所有其他值,以确保对相同类型的值执行操作。

我知道这个问题已经有答案了。我下面给出的是一些转换的例子。它对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"

最好使用下面的代码来理解隐式转换。

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]));
	}
}