如果我们将其拆分,则混乱等于:
++[[]][+[]]
+
[+[]]
在 JavaScript 中,+[] === 0 是真的。 + 将某些内容转换为数字,在这种情况下,它将归结为 +"" 或 0(请参阅下面的规范详细信息)。
因此,我们可以简化它(++ 优先于+):
++[[]][0]
+
[0]
因为[[]][0]的意思是:从[[]]获取第一个元素,所以确实:
[[]][0] 返回内部数组 ([])。由于引用,说[[]][0] === [] 是错误的,但是让我们调用内部数组A 以避免错误的表示法。
++ 在其操作数之前表示“加一并返回增加后的结果”。所以++[[]][0] 等价于Number(A) + 1(或+A + 1)。
同样,我们可以将混乱简化为更清晰的内容。让我们用[] 代替A:
(+[] + 1)
+
[0]
在+[] 可以将数组强制转换为数字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 一元 + 运算符
一元+运算符将其操作数转换为数字类型。
产生式 UnaryExpression : + UnaryExpression 的评估如下:
设 expr 为计算 UnaryExpression 的结果。
Return ToNumber(GetValue(expr)).
ToNumber() 说:
对象
应用以下步骤:
设 primValue 为 ToPrimitive(输入参数,提示字符串)。
返回 ToString(primValue)。
ToPrimitive() 说:
对象
返回对象的默认值。通过调用对象的 [[DefaultValue]] 内部方法检索对象的默认值,并传递可选提示 PreferredType。本规范为 8.12.8 中的所有原生 ECMAScript 对象定义了 [[DefaultValue]] 内部方法的行为。
[[DefaultValue]] 说:
8.12.8 [[DefaultValue]](提示)
当O的[[DefaultValue]]内部方法用hint String调用时,采取如下步骤:
令 toString 为使用参数“toString”调用对象 O 的 [[Get]] 内部方法的结果。
如果 IsCallable(toString) 为真,则
一个。令 str 为调用 toString 的 [[Call]] 内部方法的结果,O 为 this 值,参数列表为空。
b.如果 str 是原始值,则返回 str。
数组的.toString 表示:
15.4.4.2 Array.prototype.toString()
在调用toString方法时,会采取以下步骤:
令数组为对 this 值调用 ToObject 的结果。
令 func 为以“join”为参数调用数组的 [[Get]] 内部方法的结果。
如果 IsCallable(func) 为 false,则令 func 为标准内置方法 Object.prototype.toString (15.2.4.2)。
返回调用func的[[Call]]内部方法的结果,提供数组作为this值和一个空参数列表。
所以+[] 归结为+"",因为[].join() === ""。
同样,+ 定义为:
11.4.6 一元 + 运算符
一元+运算符将其操作数转换为数字类型。
产生式 UnaryExpression : + UnaryExpression 的评估如下:
设 expr 为计算 UnaryExpression 的结果。
Return ToNumber(GetValue(expr)).
ToNumber 为 "" 定义为:
StringNumericLiteral ::: [empty]的MV为0。
所以+"" === 0,因此+[] === 0。