【问题标题】:Implicit data type conversion in JavaScript when comparing integer with string using ==使用 == 比较整数和字符串时 JavaScript 中的隐式数据类型转换
【发布时间】:2011-11-29 07:44:02
【问题描述】:

代码:

var num = 20;

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

问题:

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

  2. 上面的代码将提示我一个带有消息"It works" 的警告框,表明if 测试条件评估为真。

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

【问题讨论】:

  • 我很难从 C 编程切换回 javascript 或 php,因为某些规则有一些不同,就像我的大脑已经习惯了 C 中的规则,当我尝试用javascript编写代码,我的大脑会不断思考C规则
  • 对于第 1 点,在 JavaScript 中所有数字都是浮点数,因此不需要 intfloat 促销。

标签: javascript implicit-conversion comparison-operators


【解决方案1】:

是的,等号运算符应用的所有类型转换规则都在 ECMA-262 规范中进行了描述,在 The Abstract Equality Comparison Algorithm 中。

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

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

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

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

    • 对Object执行Object-to-Primitive转换并再次比较

Object-to-Primitive 转换是通过称为ToPrimitive 的抽象操作进行的,此方法将尝试使用内部[[PrimitiveValue]] 方法将对象转换为原始值。

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

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

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

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

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

【讨论】:

    【解决方案2】:

    在 JavaScript 中,有两个运算符可用于比较两个值:===== 运算符。

    引自 JavaScript The Definitive Guide 6th Edition:

    相等运算符 == 类似于严格相等运算符 (===),但它 不那么严格。如果两个操作数的值不是同一类型, 它会尝试一些类型转换并再次尝试比较。

    严格相等运算符=== 计算其操作数,然后比较 如下两个值,不进行类型转换。

    所以我建议你一直使用=== 以避免出现以下问题:

    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.
    

    附:我可以发布书中所写的整个“比较指南”,但它太长了;)告诉我,我会为你编辑我的帖子。

    【讨论】:

    • Douglas Crockford 同意你的观点:“我的建议是永远不要使用邪恶双胞胎。相反,始终使用 ===!==。” (见stackoverflow.com/a/359509/3779853)。我喜欢这种方法,但是如果我希望 "1"1 在我的代码中的某处被认为是相等的,例如在 JSON 导入之后,我该怎么办? parseInt?
    【解决方案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]));
        	}
        }

        【讨论】:

          猜你喜欢
          • 2013-12-16
          • 1970-01-01
          • 2012-03-04
          • 2015-06-18
          • 1970-01-01
          • 2016-09-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多