如何在javascript中1 == [1]?

hma*_*ary 38 javascript arrays coercion

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

 var a = 1;
 var b = [1];
Run Code Online (Sandbox Code Playgroud)

什么会a == b;回来.

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

var a = 1;
var b = [1];
a == b;
true
Run Code Online (Sandbox Code Playgroud)

我也检查过了

var a = 1;
var b =(1);
a == b;
true
Run Code Online (Sandbox Code Playgroud)

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

Ray*_*yon 51

如果将对象与数字或字符串进行比较,JavaScript会尝试返回该对象的默认值.运算符尝试使用对象的和方法将对象转换为原始值,StringNumber值.如果转换对象的尝试失败,则会生成运行时错误.[ 参考 ]valueOftoString

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
Run Code Online (Sandbox Code Playgroud)

由于转换后的值属于类型String,因此在比较a number和a时string,会将其string转换为number值,然后应用严格比较.


Mar*_*oom 51

我没有真正了解Rayon 在将对象转换为原始值时如何解释valueOftoString发挥作用; 所以我深入研究了ECMAScript 2015规范.

警告:答案很长.

我们想检查表达式1 == [1].

12.10 Equality Operators开始,我们看到,在检索表达式值之后,最后一步是

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

抽象平等比较在第7.2.12抽象平等比较中定义.

7.2.12抽象等式比较
比较x == y,其中x和y是值,产生真或假.这样的比较如下进行:

  1. ReturnIfAbrupt(X).
  2. ReturnIfAbrupt(Y).
  3. 如果Type(x)与Type(y)相同,那么
    a.返回执行Strict Equality Comparison 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.

表达式1 == [1]属于案例10.
所以基本上,正如预期的那样,数组[1]被转换为原始类型的值.

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

抽象操作ToPrimitive接受输入参数和可选参数PreferredType.抽象操作ToPrimitive将其输入参数转换为非Object类型.

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

  1. PreferredType参数(实际上是暗示 VAR)从"默认"(因为它不通过),以"数字"转换.
  2. OrdinaryToPrimitive 用相同的参数调用.

E现在是有趣的部分,OrdinaryToPrimitive执行以下操作:

  1. 断言:类型(O)是对象
  2. 断言:Type(提示)是String,其值为"string"或"number".
  3. 如果提示是"字符串",那么
    a.让methodNames为«"toString","valueOf"».
  4. 否则,
    a.让methodNames为«"valueOf","toString"».
  5. 对于List顺序中methodNames中的每个名称,执行
    a.让方法为Get(O,name).
    湾 ReturnIfAbrupt(方法).
    C.如果IsCallable(方法)为真,那么
    ...... i.让结果为Call(方法,O).
    ...... ii.ReturnIfAbrupt(结果).
    ...... iii.**如果Type(result)不是Object,则返回结果.**
  6. 抛出TypeError异常

因此,为了转换[1]为原始值,运行时首先尝试调用valueOf.此方法返回数组本身,这是一个对象,因此通过5.c.iiitoString接下来调用该方法.
此方法以逗号分隔列表的形式返回数组的元素,因此它只返回字符串"1".

因此,我们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>
Run Code Online (Sandbox Code Playgroud)

  • 很好的答案!`1 == [1]`=`1 == [1] .valueOf().toString()`=`1 =="1"`=`1 == 1` (3认同)
  • @MichaelDibbets谢谢,但我的观点是`1 == [1]`=>`1 == [1] .toString()`=>`1 =="1"`=`1 == 1` (2认同)

gdg*_*dgr 13

这是由于进行了比较的类型.

在javascript中,可以使用其中一个=====进行比较.在三等于的情况下,这就是所谓的没有类型强制的平等,换句话说,它是一种严格的比较.

与类型强制相等

相反,这意味着使用double equals操作数类型强制相等.

这是什么意思?

简单地说,这意味着javascript将使用内置方法将值转换为基本类型,以便进行比较.具体来说,那些方法是.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
Run Code Online (Sandbox Code Playgroud)

人机工程学:

1 == [1] // true
1 === [1] // false, because they are of a different type
Run Code Online (Sandbox Code Playgroud)