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

2022-08-29 21:56:34

这是有效的,并在JavaScript中返回字符串(此处有更多示例):"10"

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

为什么?这是怎么回事?


答案 1

如果我们把它分开,混乱等于:

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

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

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

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

因为 means: 从 中获取第一个元素,这是真的:[[]][0][[]]

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

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

同样,我们可以将混乱简化为更清晰的东西。让我们用以下代码替换回来:[]A

(+[] + 1)
+
[0]

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

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

让我们进一步简化它:

1
+
[0]

此外,这在 JavaScript 中是正确的:,因为它将数组与一个元素联接在一起。连接将连接由 分隔的元素。使用一个元素,您可以推断出此逻辑将产生第一个元素本身。[0] == "0",

在本例中,将看到两个操作数:一个数字和一个数组。它现在正试图将两者强制为同一类型。首先,将数组强制转换为字符串,接下来,将数字强制转换为字符串()。数字 + 字符串 === 字符串+"0""1"

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

规格详情:+[]

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

11.4.6 一元 +运算符

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

生产一元表达式 : + 一元表达式的评估如下:

  1. 让 expr 是计算一元表达式的结果。

  2. Return ToNumber(GetValue(expr)).

ToNumber()说:

对象

应用以下步骤:

  1. Let primValue be ToPrimitive(input argument, hint String)。

  2. 返回String(primValue)。

ToPrimitive()说:

对象

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

[[DefaultValue]]说:

8.12.8 [[默认值]] (提示)

当使用提示字符串调用 O 的 [[DefaultValue]] 内部方法时,将执行以下步骤:

  1. 让 toString 成为调用对象 O 的 [[Get]] 内部方法的结果,参数为“toString”。

  2. 如果 IsCallable(toString) 为真,则

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

b.如果 str 是基元值,则返回 str。

数组的 表示:.toString

15.4.4.2 Array.prototype.toString ( )

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

  1. 让数组成为在此值上调用 ToObject 的结果。

  2. 让 func 成为调用数组的 [[Get]] 内部方法的结果,参数为“join”。

  3. 如果 IsCallable(func) 是 false,那么让 func 成为标准的内置方法 Object.prototype.toString (15.2.4.2)。

  4. 返回调用函数的 [[Call]] 内部方法的结果,该函数提供数组作为 this 值和空参数列表。

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

同样,定义为:+

11.4.6 一元 +运算符

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

生产一元表达式 : + 一元表达式的评估如下:

  1. 让 expr 是计算一元表达式的结果。

  2. Return ToNumber(GetValue(expr)).

ToNumber定义为:""

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

所以,因此。+"" === 0+[] === 0


答案 2
++[[]][+[]] => 1 // [+[]] = [0], ++0 = 1
[+[]] => [0]

然后我们有一个字符串串联

1+[0].toString() = 10