一尘不染

为什么 ++[[]][+[]]+[+[]] 返回字符串“10”?

javascript

"10"这是有效的,并返回JavaScript中的字符串:

console.log(++[[]][+[]]+[+[]])

为什么?这里发生了什么?


阅读 147

收藏
2022-02-16

共1个答案

一尘不染

如果我们将其拆分,则混乱等于:

++[[]][+[]]
+
[+[]]

在 JavaScript 中,确实如此+[] === 0+将某物转换为数字,在这种情况下,它将归结为+""0(请参阅下面的规范详细信息)。

因此,我们可以简化它(++优先于+):

++[[]][0]
+
[0]

因为[[]][0]意味着:从 中获取第一个元素[[]],所以确实:

[[]][0]返回内部数组 ( [])。由于引用,说 是错误的[[]][0] === [],但让我们调用内部数组A以避免错误的表示法。

++在其操作数之前表示“递增一并返回递增的结果”。所以++[[]][0]等价于Number(A) + 1(或+A + 1)。

同样,我们可以将混乱简化为更清晰的内容。让我们[]换回A

(+[] + 1)
+
[0]

+[]将数组强制转换为 number之前0,需要先将其强制转换为字符串,即"", 再次。最后,1添加 ,结果为1

  • (+[] + 1) === (+"" + 1)
  • (+"" + 1) === (0 + 1)
  • (0 + 1) === 1

让我们进一步简化它:

1
+
[0]

此外,在 JavaScript: 中也是如此[0] == "0",因为它使用一个元素连接数组。加入将连接由 分隔的元素,。使用一个元素,您可以推断此逻辑将导致第一个元素本身。

在这种情况下,+看到两个操作数:一个数字和一个数组。它现在正试图将两者强制为同一类型。首先,将数组强制转换为字符串"0",然后将数字强制转换为字符串 ( "1")。数字+字符串===字符串

"1" + "0" === "10" // Yay!

规格详细信息+[]

这是一个迷宫,但要做到这一点+[],首先它被转换为字符串,因为这+就是说:

11.4.6 一元+运算符

一元 + 运算符将其操作数转换为 Number 类型。

产生式 UnaryExpression : + UnaryExpression 的评估如下:

  1. 令 expr 为计算 UnaryExpression 的结果。
  2. 返回 ToNumber(GetValue(expr))。

ToNumber()说:

目的

应用以下步骤:

  1. 设 primValue 为 ToPrimitive(输入参数,提示字符串)。
  2. 返回 ToString(primValue)。

ToPrimitive()说:

目的

返回对象的默认值。通过调用对象的 [[DefaultValue]] 内部方法检索对象的默认值,并传递可选提示 PreferredType。本规范为 8.12.8 中的所有原生 ECMAScript 对象定义了 [[DefaultValue]] 内部方法的行为。

[[DefaultValue]]说:

8.12.8 [[DefaultValue]](提示)

当使用提示String调用O的[[DefaultValue]]内部方法时,采取以下步骤:

  1. 令 toString 为使用参数“toString”调用对象 O 的 [[Get]] 内部方法的结果。
  2. 如果 IsCallable(toString) 为真,则

一个。令 str 为调用 toString 的 [[Call]] 内部方法的结果,其中 O 作为 this 值和一个空参数列表。

湾。如果 str 是原始值,则返回 str。

.toString数组的 说:

15.4.4.2 Array.prototype.toString()

当调用 toString 方法时,会执行以下步骤:

  1. 让 array 成为对 this 值调用 ToObject 的结果。
  2. 令 func 为使用参数“join”调用数组的 [[Get]] 内部方法的结果。
  3. 如果 IsCallable(func) 为 false,则令 func 为标准内置方法 Object.prototype.toString (15.2.4.2)。
  4. 返回调用 func 的 [[Call]] 内部方法的结果,提供数组作为 this 值和一个空参数列表。

所以+[]归结为+"",因为[].join() === ""

同样,+定义为:

11.4.6 一元+运算符

一元 + 运算符将其操作数转换为 Number 类型。

产生式 UnaryExpression : + UnaryExpression 的评估如下:

  1. 令 expr 为计算 UnaryExpression 的结果。
  2. 返回 ToNumber(GetValue(expr))。

ToNumber定义为""

StringNumericLiteral ::: [empty] 的 MV 为 0。

如此+"" === 0,如此,如此+[] === 0

2022-02-16