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

时间:2021-07-03 15:29:44

The code:

代码:

var num = 20;

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

The question:

一个问题:

  1. In C programming we have a rule name data type promotion, where when there's a mix of data type (example: addition of integer and floating point), the integer will first converted to floating point before the addition is being carry out.

    在C编程中,我们有一个规则名称数据类型提升,当有数据类型混合时(例如:添加整数和浮点数),该整数将首先转换为浮点数,然后再进行添加。

  2. The code above will prompt me an alert box with the message "It works" that shows the if test condition is evaluate to true.

    上面的代码将提示我一个警告框,其中包含“It works”,显示如果测试条件为true。

  3. For loosely typed JavaScript, I'm just curious: is there any rule like C that determines which conversion will be carry out in which situation? Besides that, the JavaScript code above converts num variable value from an integer value to string value before making comparison or vice versa?

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

5 个解决方案

#1


19  

Yes, all the rules of type conversion applied by the equals operator are described on the ECMA-262 specification, in The Abstract Equality Comparison Algorithm.

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

The algorithm might look quite complex but it can be summarized to the following cases:

该算法可能看起来相当复杂,但可以总结为以下情况:

  1. The type the two operands is the same:

    两个操作数的类型相同:

    • For primitives (String, Number, Boolean, Null, Undefined)
      • Return true if the value is exactly the same
      • 如果值完全相同,则返回true
    • 对于原语(String、Number、Boolean、Null、Undefined),如果值完全相同,则返回true。
    • For the Object type
      • Return true if the two references point to the same object
      • 如果两个引用指向同一个对象,则返回true。
    • 对于对象类型返回true,如果两个引用指向同一个对象。
  2. If the types of the two operands differ

    如果两个操作数的类型不同

    • If the type of one operand is either Null or Undefined
      • Return true only if the other operand value is either null or undefined
      • 只有当其他操作数值为空或未定义时,才返回true
    • 如果一个操作数的类型是Null或Undefined,那么只有当另一个操作数值是Null或Undefined时才返回true
    • If one of the operands is of type Boolean or Number
      • (after some steps) Convert the other operand to Number and compare
      • (经过一些步骤)将另一个操作数转换为Number并进行比较
    • 如果其中一个操作数类型为Boolean或Number(经过一些步骤),则将另一个操作数转换为Number并进行比较
  3. If one of the operands is an Object and the other is a primitive

    如果一个操作数是对象,另一个是原语

    • Perform Object-to-Primitive conversion on the Object and compare again
    • 在对象上执行对象到原语的转换并再次进行比较

The Object-to-Primitive conversion is made through an abstract operation called ToPrimitive, this method will try to convert the object to a primitive value, using the internal [[PrimitiveValue]] method.

对象到原语的转换是通过一个名为ToPrimitive的抽象操作进行的,该方法将尝试使用内部的[[原语]]方法将对象转换为原语值。

This will try to ejecute the object's valueOf and toString methods, and it will take the value of the first that returns a primitive value.

这将尝试抛出对象的valueOf和toString方法,并取第一个返回原始值的值。

In the case those two methods don't return a primitive, or they aren't callable, a TypeError is thrown, e.g.:

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

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

The above statement will produce a TypeError because the default Object.prototype.valueOf method doesn't do anything more than actually the same object instance (this, not a primitive value) and we are setting an own toString property that's not a function.

由于默认的Object.prototype,上面的语句将产生一个TypeError。valueOf方法只做了实际上相同的对象实例(这个,不是原语值),我们正在设置一个自己的toString属性,它不是函数。

A friend made small tool that might be interesting to you, it shows all the steps and recursive comparisons made between types:

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

#2


6  

In JavaScript, there are two operators that can be used to compare two values: the == and === operators.

在JavaScript中,有两个操作符可以用来比较两个值:==和===操作符。

Quoted from JavaScript The Definitive Guide 6th Edition:

引用JavaScript的权威指南第6版:

The equality operator == is like the strict equality operator (===), but it is less strict. If the values of the two operands are not the same type, it attempts some type conversions and tries the comparison again.

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

And

The strict equality operator === evaluates its operands, and then compares the two values as follows, performing no type conversion.

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

So I suggest that you use === all the time to avoid problems like:

因此,我建议您一直使用=== =来避免以下问题:

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. I could post the entire "comparison guidelines" as written in the book but it's too long ;) Just tell me and I'll edit my post for you.

附注:我可以贴出书中所写的全部“比较指南”,但是太长了;告诉我,我会帮你编辑我的文章。

#3


2  

Avoid implicit type conversion in JavaScript. Always take steps to test and/or convert individual values before comparing them to ensure you are comparing apples to apples. Always test explicitly for undefined to determine if a value or property has a value, use null to indicate that object variables or properties do not refer to any object, and convert & compare all other values to ensure operations are performed against values of the same type.

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

#4


0  

I know the question has been answered. What I have given below is an example of few conversions. It will be useful for someone who is new to JavaScript. The below output can be compared with the general algorithm for an easy understanding.

我知道这个问题已经得到了回答。下面我给出的是一个很少转换的例子。对于刚接触JavaScript的人来说,这是非常有用的。下面的输出可以与通用算法进行比较,便于理解。

The code:

代码:

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

The output:

输出:

"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


0  

Better use below code for understanding implicit conversion.

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

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

#1


19  

Yes, all the rules of type conversion applied by the equals operator are described on the ECMA-262 specification, in The Abstract Equality Comparison Algorithm.

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

The algorithm might look quite complex but it can be summarized to the following cases:

该算法可能看起来相当复杂,但可以总结为以下情况:

  1. The type the two operands is the same:

    两个操作数的类型相同:

    • For primitives (String, Number, Boolean, Null, Undefined)
      • Return true if the value is exactly the same
      • 如果值完全相同,则返回true
    • 对于原语(String、Number、Boolean、Null、Undefined),如果值完全相同,则返回true。
    • For the Object type
      • Return true if the two references point to the same object
      • 如果两个引用指向同一个对象,则返回true。
    • 对于对象类型返回true,如果两个引用指向同一个对象。
  2. If the types of the two operands differ

    如果两个操作数的类型不同

    • If the type of one operand is either Null or Undefined
      • Return true only if the other operand value is either null or undefined
      • 只有当其他操作数值为空或未定义时,才返回true
    • 如果一个操作数的类型是Null或Undefined,那么只有当另一个操作数值是Null或Undefined时才返回true
    • If one of the operands is of type Boolean or Number
      • (after some steps) Convert the other operand to Number and compare
      • (经过一些步骤)将另一个操作数转换为Number并进行比较
    • 如果其中一个操作数类型为Boolean或Number(经过一些步骤),则将另一个操作数转换为Number并进行比较
  3. If one of the operands is an Object and the other is a primitive

    如果一个操作数是对象,另一个是原语

    • Perform Object-to-Primitive conversion on the Object and compare again
    • 在对象上执行对象到原语的转换并再次进行比较

The Object-to-Primitive conversion is made through an abstract operation called ToPrimitive, this method will try to convert the object to a primitive value, using the internal [[PrimitiveValue]] method.

对象到原语的转换是通过一个名为ToPrimitive的抽象操作进行的,该方法将尝试使用内部的[[原语]]方法将对象转换为原语值。

This will try to ejecute the object's valueOf and toString methods, and it will take the value of the first that returns a primitive value.

这将尝试抛出对象的valueOf和toString方法,并取第一个返回原始值的值。

In the case those two methods don't return a primitive, or they aren't callable, a TypeError is thrown, e.g.:

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

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

The above statement will produce a TypeError because the default Object.prototype.valueOf method doesn't do anything more than actually the same object instance (this, not a primitive value) and we are setting an own toString property that's not a function.

由于默认的Object.prototype,上面的语句将产生一个TypeError。valueOf方法只做了实际上相同的对象实例(这个,不是原语值),我们正在设置一个自己的toString属性,它不是函数。

A friend made small tool that might be interesting to you, it shows all the steps and recursive comparisons made between types:

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

#2


6  

In JavaScript, there are two operators that can be used to compare two values: the == and === operators.

在JavaScript中,有两个操作符可以用来比较两个值:==和===操作符。

Quoted from JavaScript The Definitive Guide 6th Edition:

引用JavaScript的权威指南第6版:

The equality operator == is like the strict equality operator (===), but it is less strict. If the values of the two operands are not the same type, it attempts some type conversions and tries the comparison again.

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

And

The strict equality operator === evaluates its operands, and then compares the two values as follows, performing no type conversion.

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

So I suggest that you use === all the time to avoid problems like:

因此,我建议您一直使用=== =来避免以下问题:

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. I could post the entire "comparison guidelines" as written in the book but it's too long ;) Just tell me and I'll edit my post for you.

附注:我可以贴出书中所写的全部“比较指南”,但是太长了;告诉我,我会帮你编辑我的文章。

#3


2  

Avoid implicit type conversion in JavaScript. Always take steps to test and/or convert individual values before comparing them to ensure you are comparing apples to apples. Always test explicitly for undefined to determine if a value or property has a value, use null to indicate that object variables or properties do not refer to any object, and convert & compare all other values to ensure operations are performed against values of the same type.

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

#4


0  

I know the question has been answered. What I have given below is an example of few conversions. It will be useful for someone who is new to JavaScript. The below output can be compared with the general algorithm for an easy understanding.

我知道这个问题已经得到了回答。下面我给出的是一个很少转换的例子。对于刚接触JavaScript的人来说,这是非常有用的。下面的输出可以与通用算法进行比较,便于理解。

The code:

代码:

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

The output:

输出:

"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


0  

Better use below code for understanding implicit conversion.

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

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