在JavaScript中如何1 == ?

最近我在接受采访时被问到这个问题。

var a = 1; var b = [1]; 

什么将a == b; 返回。

当我在我的Chrome浏览器控制台上查看时,我得到了这个。

 var a = 1; var b = [1]; a == b; true 

我也检查过

 var a = 1; var b =(1); a == b; true 

我知道b是一个大小为1的数组。这是否意味着数组的大小被分配给b。 我真的很困惑。 任何人都可以解释我的逻辑?

如果一个对象与一个数字或string进行比较,JavaScript会尝试返回该对象的默认值。 运算符尝试使用对象的valueOftoString方法将对象转换为原始值( String或数值)。 如果尝试转换对象失败,则会生成运行时错误。[ Ref ]

 var a = 1; var b = [1]; //What is happening when `(a==b)` //typeof a; ==> number //typeof b; ==>object //Object is converted to Primitive using `valueOf` and `toString` methods of the objects var val = b.valueOf().toString(); console.log('Values after conversion is: ' + val + ' And typeof converted value is: ' + typeof val); //typeof val; ==> string //a == b; will be evaluated as `true` because `'1' == 1` hence.. console.log(a == b); //'1'==1 ==> true 

我从Rayon的回答中并没有真正理解valueOftoString如何在将对象转换为原始值时发挥作用; 所以我深入研究了ECMAScript 2015规范。

警告 :长答案。

我们要检查expression式1 == [1]

12.10等式操作符开始,我们看到,在检索expression式值之后,最后一步是

  1. 返回执行抽象平等比较rval == lval的结果

抽象平等比较在第7.2.12章“ 抽象平等比较”中定义。

7.2.12摘要平等比较
比较x == y,其中x和y是值,产生true或false。 这样的比较如下进行:

  1. ReturnIfAbrupt(X)。
  2. ReturnIfAbrupt(Y)。
  3. 如果types(x)与types(y)相同,则
    一个。 返回执行严格平等比较x === y的结果。
  4. 如果x为null且y未定义,则返回true。
  5. 如果x未定义且y为null,则返回true。
  6. 如果Type(x)是Number和Type(y)是String,则返回比较结果x == ToNumber(y)。
  7. 如果Type(x)是String而Type(y)是Number,则返回比较结果ToNumber(x)== y。
  8. 如果Type(x)是布尔型,则返回比较结果ToNumber(x)== y。
  9. 如果Type(y)是布尔型,则返回比较结果x == ToNumber(y)。
  10. 如果Type(x)是String,Number或Symbol且Type(y)是Object,则返回比较结果x == ToPrimitive(y)。
  11. 如果Type(x)是Object且Type(y)是String,Number或Symbol,则返回比较结果ToPrimitive(x)== y。
  12. 返回false。

expression式1 == [1]属于情况10
所以基本上,正如所料,数组[1]被转换为原始types的值。

ToPrimitive定义在7.1.1 ToPrimitive(input [,PreferredType])

抽象操作ToPrimitive接受一个input参数和一个可选的参数PreferredType。 抽象操作ToPrimitive将其input参数转换为非对象types。

我没有包括完整的引文, 因为这个例子中唯一有趣的部分是:

  1. PreferredType参数(实际上是一个提示variables)从“默认”(因为它不被传递)转换为“数字”。
  2. OrdinaryToPrimitive被调用相同的参数。

E现在有趣的部分, OrdinaryToPrimitive做到以下几点:

  1. 断言:types(O)是对象
  2. 断言:types(提示)是string,其值是“string”或“数字”。
  3. 如果提示是“string”,那么
    一个。 让methodNames成为«“toString”,“valueOf”»。
  4. 其他,
    一个。 让methodNames是«“valueOf”,“toString”»。
  5. 对于列表顺序中的methodNames中的每个名称,请执行
    一个。 让方法是Get(O,名称)。
    湾 ReturnIfAbrupt(方法)。
    C。 如果IsCallable(method)是真的,那么
    … 一世。 让结果被调用(方法,O)。
    ii。 ReturnIfAbrupt(结果)。
    iii。 **如果Type(结果)不是Object,则返回结果。 **
  6. 抛出一个TypeErrorexception

所以为了将[1]转换为原始值,运行时首先要调用valueOf 。 这个方法返回数组本身,这是一个对象,所以通过5.c.iii方法toString被下一个调用。
此方法以逗号分隔列表的forms返回数组的元素,所以它只返回string"1"

所以我们减less比较1 == "1" ,根据抽象平等比较的规则,点6,意味着将"1"转换为数字1而不是执行平凡的比较1 = 1

邀请可疑读者检查严格平等比较是如何在标准中实际定义的。


你可以玩转换为更好的理解他们,在这里一个示例游乐场的HTML文件

 <html> <head><title>title</title></head> <body> <script> var old_valueOf = Array.prototype.valueOf; var old_toString = Array.prototype.toString; Array.prototype.valueOf = function(){ console.log("Array::valueOf"); return old_valueOf.apply(this); }; Array.prototype.toString = function(){ console.log("Array::toString"); return old_toString.apply(this); }; console.log(1 == [1]); //Array::valueOf, Array::toString, true Array.prototype.valueOf = function(){ console.log("Array::valueOf"); return 2; }; console.log(1 == [1]); //Array::valueOf, false Array.prototype.valueOf = function(){ console.log("Array::valueOf"); return {}; }; Array.prototype.toString = function(){ console.log("Array::toString"); return {} }; console.log(1 == [1]); //Array::valueOf, Array::toString, Uncaught TypeError: Cannot convert object to primitive value </script> </body> </html> 

这是由于正在进行比较的types。

在JavaScript中,可以使用=====进行比较。 在三重平等的情况下,这就是所谓的平等types强制 ,换句话说,这是一个严格的比较。

平等与types强制

相反,这意味着使用double等于操作数是强制types相等的。

这是什么意思?

简而言之,这意味着JavaScript将使用内置方法来将值转换为原始types,以供比较。 具体来说,这些方法是.valueOf().toString()

这里有些例子:

 0 == false // true, auto type coercion 0 === false // false, because they are of a different type 1 == "1" // true, auto type coercion 1 === "1" // false, because they are of a different type 

人机工程学:

 1 == [1] // true 1 === [1] // false, because they are of a different type