【问题标题】:How is 1 == [1] in javascript? [duplicate]javascript中的1 == [1]如何? [复制]
【发布时间】:2016-08-29 12:20:16
【问题描述】:

最近在一次采访中被问到这个问题。

 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。我真的很困惑。谁能解释一下逻辑?

【问题讨论】:

  • 我不知道你为什么会对那个使用括号的例子感到惊讶?如果你在一张纸上写下方程(1) = 1,你会立即说这个方程是正确的。为什么你认为在 Javascript 中做它的等价物时会不是这样?
  • @Paul 我很确定 OP 意味着 var i = 1;var a = 1; 否则这将是一个微不足道的面试问题。
  • @nisar 这是一个糟糕的编辑:我们不知道这是否是实际的面试问题 - 只有 OP 才能解决这个问题,如果它确实被破坏了。参见上面的 cmets 讨论
  • 这是一个让我很生气的面试问题。这些知识有什么实际用途?
  • 我同意马特。如果有人不断地遇到这些怪癖到他们知道答案的地方,我会质疑他们甚至在编程方面有多好。

标签: javascript arrays coercion


【解决方案1】:

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

警告:答案很长。

我们要检查表达式1 == [1]

12.10 等式运算符开始,我们看到,在检索表达式值之后,最后一步是

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

抽象等式比较7.2.12 抽象等式比较一章中定义。

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

  1. ReturnIfAbrupt(x)。
  2. ReturnIfAbrupt(y)。
  3. 如果 Type(x) 与 Type(y) 相同,则
    一种。返回执行严格等式比较 x === y 的结果。
  4. 如果 x 为空且 y 未定义,则返回 true。
  5. 如果 x 未定义且 y 为空,则返回 true。
  6. 如果 Type(x) 是 Number 并且 Type(y) 是 String,则返回比较结果 x == ToNumber(y)。
  7. 如果 Type(x) 是 String 且 Type(y) 是 Number,则返回比较结果 ToNumber(x) == y。
  8. 如果 Type(x) 是 Boolean,则返回 ToNumber(x) == y 的比较结果。
  9. 如果 Type(y) 是 Boolean,则返回比较结果 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] 属于case 10
所以基本上,正如预期的那样,数组[1] 被转换为原始类型的值。

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

抽象操作 ToPrimitive 接受一个输入参数和一个可选参数 PreferredType。这 抽象操作 ToPrimitive 将其输入参数转换为非对象类型。

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

  1. PreferredType 参数(实际上是一个 hint 变量)从“默认”(因为未传递)转换为“数字”。
  2. OrdinaryToPrimitive 使用相同的参数调用。

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

  1. 断言:类型(O)是对象
  2. 断言:类型(提示)是字符串,其值是“字符串”或“数字”。
  3. 如果提示是“字符串”,则
    一种。让 methodNames 为 «"toString", "valueOf"»。
  4. 否则,
    一种。 让 methodNames 为 «"valueOf", "toString"»。
  5. 对于方法名称中的每个名称,按列表顺序执行
    一种。让方法为 Get(O, name)。
    湾。 ReturnIfAbrupt(方法)。
    C。如果 IsCallable(method) 为真,则
    ... 一世。让结果为 Call(method, O)。
    ... 二。 ReturnIfAbrupt(结果)。
    ... 三。 **如果 Type(result) 不是 Object,则返回结果。 **
  6. 抛出 TypeError 异常

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

所以我们减少了比较1 == "1",根据抽象平等比较的规则,第 6 点意味着将"1" 转换为数字1,而不是执行琐碎的比较@987654335 @。

请可疑的读者检查严格相等比较在标准中的实际定义。


您可以使用这些转换来更好地理解它们,这里是一个示例游乐场 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>

【讨论】:

  • 优秀的答案! 1 == [1] = 1 == [1].valueOf().toString() = 1 == "1" = 1 == 1
  • @MichaelDibbets 谢谢,但我的意思是1 == [1] => 1 == [1].toString() => 1 == "1" = 1 == 1
  • 嗯,是的,但是 valueOf 仍然被称为。我只是试图使程序流程富有洞察力。想象一下已经覆盖了 valueOf 方法 ;-) x = [1];x.valueOf = function(){return 'x';}
  • 我的意思是 :-) x=[1];a=1;console.log(a==x);x.valueOf = function(){return 'x';};console.log(a==x);
  • 非常详细的回答:)
【解决方案2】:

如果将对象与数字或字符串进行比较,JavaScript 会尝试返回该对象的默认值。运算符尝试使用对象的valueOftoString 方法将对象转换为原始值、StringNumber 值。如果转换对象的尝试失败,则会生成运行时错误。[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

由于转换后的值是 String 类型,在比较 numberstring 时,string 将转换为 number 值,然后应用严格比较。

【讨论】:

  • 所以这意味着[1]被转换为字符串"1"被转换为整数1?对吗?
  • 否 - 阅读 OP 中的 cmets。
  • 如果仔细观察,a 是未定义的;定义的原始值实际上是 i.
  • JavaScript attempts to return the default value for the object. 上述情况下的默认值是什么意思?
  • 对我来说没有意义的一件事是您已将 b 的原始值直接转换为 var val = b.valueOf().toString(); 行中的字符串,因此 console.log(typeof val) 肯定会返回string?我错过了什么吗?
【解决方案3】:

这是由于所进行的比较类型所致。

在 javascript 中,可以使用===== 进行比较。在三等号的情况下,这就是所谓的equality without type coercion,换句话说,这是一个严格的比较。

类型强制的相等性

相反,这意味着使用双等号操作数是等于类型的强制。

这是什么意思?

简单地说,这意味着 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

尔格:

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

【讨论】:

  • 非常感谢您对否决票的解释,如果有什么可以增加它的价值,我会很高兴地改进我的回答。
  • 我没有投反对票,但我猜这是因为只介绍了类型转换正在进行,而没有解释发生类型转换时[1] 是如何变成1 的。 +1 虽然用于展示 ===== 之间的区别
  • 我想如果你要从字面上回答这个问题,OP 确实会说“如何”,但我认为这可能是语言障碍问题,而问题实际上更多的是“为什么” ,考虑到她/他被一位面试官问过这个问题,我认为他正在探索这个确切的知识。 (比 如何 javascript 从根本上处理这种细微差别,我更期待。)不过,我认为其他回答者很好地解释了这一点,我不想复制!感谢您的反馈@jdkorv11 :)
猜你喜欢
  • 2014-11-11
  • 1970-01-01
  • 1970-01-01
  • 2011-12-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-29
  • 2020-06-26
相关资源
最近更新 更多