javascript - javascript 中的 1 == [1] 是怎样的?

标签 javascript arrays coercion

<分区>

最近我在面试中被问到这个问题。

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

最佳答案

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

警告:答案很长。

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

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

  1. Return the result of performing Abstract Equality Comparison rval == lval

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

7.2.12 Abstract Equality Comparison
The comparison x == y, where x and y are values, produces true or false. Such a comparison is performed as follows:

  1. ReturnIfAbrupt(x).
  2. ReturnIfAbrupt(y).
  3. If Type(x) is the same as Type(y), then
    a. Return the result of performing Strict Equality Comparison x === y.
  4. If x is null and y is undefined, return true.
  5. If x is undefined and y is null, return true.
  6. If Type(x) is Number and Type(y) is String, return the result of the comparison x == ToNumber(y).
  7. If Type(x) is String and Type(y) is Number, return the result of the comparison ToNumber(x) == y.
  8. If Type(x) is Boolean, return the result of the comparison ToNumber(x) == y.
  9. If Type(y) is Boolean, return the result of the comparison x == ToNumber(y).
  10. If Type(x) is either String, Number, or Symbol and Type(y) is Object, then return the result of the comparison x == ToPrimitive(y).
  11. If Type(x) is Object and Type(y) is either String, Number, or Symbol, then return the result of the comparison ToPrimitive(x) == y.
  12. Return false.

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

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

The abstract operation ToPrimitive takes an input argument and an optional argument PreferredType. The abstract operation ToPrimitive converts its input argument to a non-Object type.

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

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

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

  1. Assert: Type(O) is Object
  2. Assert: Type(hint) is String and its value is either "string" or "number".
  3. If hint is "string", then
    a. Let methodNames be «"toString", "valueOf"».
  4. Else,
    a. Let methodNames be «"valueOf", "toString"».
  5. For each name in methodNames in List order, do
    a. Let method be Get(O, name).
    b. ReturnIfAbrupt(method).
    c. If IsCallable(method) is true, then
    ... i. Let result be Call(method, O).
    ... ii. ReturnIfAbrupt(result).
    ... iii. **If Type(result) is not Object, return result. **
  6. Throw a TypeError exception

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

所以我们减少了比较1 == "1",根据抽象相等比较的规则,第 6 点,意味着转换 "1" 转换为数字 1,然后执行简单的比较 1 = 1

邀请可疑的读者检查标准中实际上如何定义严格相等比较


您可以尝试这种转换以更好地理解它们,这里是一个示例 playground 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>

关于javascript - javascript 中的 1 == [1] 是怎样的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37021335/

相关文章:

javascript - 刷新页面时保持音频播放

javascript - 如何遍历以数组作为属性的对象

R: "In eval(ei, envir) : NAs introduced by coercion"是什么原因导致的?

JavaScript 强制 : Console vs Script

javascript - Spree - 无法覆盖 js.coffee 文件

javascript - 自定义 jquery 或 javascript 从字符串扩展中删除特殊字符

python - 选择行,使特定列包含列表中的值

php - 数组中的值是字符串而不是整数

javascript - 按类型排除 React Router 中路径参数的值

javascript - 在 c3.js - d3.js 中将第 2 个字母以粗体显示