这是有效的,并返回"10"JavaScript中的字符串
"10"
console.log(++[[]][+[]]+[+[]])
为什么?这是怎么回事
如果我们将其拆分,则混乱等于:
++[[]][+[]] + [+[]]
在JavaScript中,确实是这样+[]===0。+将某物转换为数字,在这种情况下,它将降为+""或0(请参见下面的规范详细信息)。
+[]===0
+
+""
0
因此,我们可以简化它(++优先于+):
++
++[[]][0] + [0]
因为[[]][0]意思是:从中获取第一个元素[[]],所以确实:
[[]][0]
[[]]
[[]][0]返回内部数组([])。由于引用,说错了[[]][0]===[],但是让我们调用内部数组A以避免错误的表示法。 ++在其操作数之前表示“加1并返回加结果”。因此++[[]][0]等于Number(A) + 1(或+A + 1)。
[]
[[]][0]===[]
A
++[[]][0]
Number(A) + 1
+A + 1
同样,我们可以将混乱简化为更清晰的内容。让我们替换[]为A:
(+[] + 1) + [0]
在+[]将数组强制转换为number之前0,需要先将其强制转换为字符串,即""再次。最后1添加,结果为1。
+[]
""
1
(+[] + 1) === (+"" + 1)
(+"" + 1) === (0 + 1)
(0 + 1) === 1
让我们进一步简化一下:
1 + [0]
同样,在JavaScript:中也是如此[0]=="0",因为它是将一个元素与一个数组连接在一起。连接将连接由分隔的元素,。使用一个元素,您可以推断出此逻辑将导致第一个元素本身。
[0]=="0"
,
在这种情况下,+将看到两个操作数:一个数字和一个数组。现在,它试图将两者强制转换为同一类型。首先,将数组强制转换为字符串"0",然后将数字强制转换为字符串("1")。 Number+字符串===String。
"0"
"1"
===
"1" + "0" === "10" // Yay!
规格详细信息+[]:
这+[]真是一个迷宫,但要做到这一点,首先要将其转换为字符串,因为这是这样+说的:
11.4.6一元+运算符
一元+运算符将其操作数转换为Number类型。
产生UnaryExpression:+ UnaryExpression的评估如下:
令expr为评估UnaryExpression的结果。
返回ToNumber(GetValue(expr))。
ToNumber() 说:
ToNumber()
宾语
应用以下步骤:
令primValue为ToPrimitive(输入参数,提示字符串)。
返回ToString(primValue)。
ToPrimitive() 说:
ToPrimitive()
返回对象的默认值。通过调用对象的[[DefaultValue]]内部方法并传递可选提示PreferredType来检索对象的默认值。本规范为8.12.8中的所有本机ECMAScript对象定义了[[DefaultValue]]内部方法的行为。
[[DefaultValue]] 说:
[[DefaultValue]]
8.12.8 [[DefaultValue]](提示)
使用提示字符串调用O的[[DefaultValue]]内部方法时,将执行以下步骤:
令toString为使用参数“ toString”调用对象O的[[Get]]内部方法的结果。
如果IsCallable(toString)为true,
一个。令str为调用toString的[[Call]]内部方法的结果,其中O为this值,并且参数列表为空。
b。如果str是原始值,则返回str。
该.toString数组的说:
.toString
15.4.4.2 Array.prototype.toString()
调用toString方法时,将执行以下步骤:
令array为在this值上调用ToObject的结果。
令func为使用参数“ join”调用array的[[Get]]内部方法的结果。
3. 如果IsCallable(func)为false,则将func设为标准的内置方法Object.prototype.toString(15.2.4.2)。
所以+[]归结为+"",因为[].join() === ""。
[].join() === ""
同样,+定义为:
ToNumber被定义为"":
ToNumber
StringNumericLiteral ::: [空]的MV为0。
如此+"" === 0,如此+[] === 0。
+"" === 0
+[] === 0