为什么++ [[]] [+ []] + [+ []]返回字符串“10”? [英] Why does ++[[]][+[]]+[+[]] return the string "10"?
问题描述
这是有效的,并在JavaScript中返回<$ href =http://sla.ckers.org/forum/read.php? 24,33349,33405rel =noreferrer>此处有更多示例):
的console.log(++ [[]] [+ [] + [+ []])
为什么?这里发生了什么?
如果我们将其拆分,那么这个混乱就等于:
++ [[]] [+ []]
+
[+ []]
在JavaScript中, + [] === 0
确实如此。 +
将某些内容转换为数字,在这种情况下,它会降至 +
或 0
(参见下面的规范详情)。
因此,我们可以简化它( ++
优先于 +
):
++ [ []] [0]
+
[0]
因为 [[]] [0]
表示:从 [[]]
获取第一个元素,这是真的:
-
[[]] [0]
返回内部数组([]
)。由于引用,说[[]] [0] === []
是错误的,但让我们调用内部数组A
避免错误的表示法。 -
++ [[]] [0] == A + 1
,因为++
表示'递增1'。 -
++ [[]] [0] === +(A + 1)
;换句话说,它总是一个数字(+1
不一定返回一个数字,而++
总是确实 - 感谢Tim Down指出这一点。)
同样,我们可以将混乱简化为更清晰的东西。让我们用 []
代替 A
:
+([] + 1)
+
[0]
在JavaScript中,这也是正确的: [] + 1 ===1
,因为 [] ==
(加入一个空数组),所以:
-
+([] + 1)=== +(+ 1)
, -
+(+ 1)=== + (1)
, -
+(1)=== 1
让我们进一步简化:
1
+
[0]
此外,这在JavaScript中也是如此: [0] ==0
,因为它正在使用一个元素加入一个数组。连接将连接由,
分隔的元素。使用一个元素,您可以推断出这个逻辑将导致第一个元素本身。
所以,最后我们得到(number + string = string):
1
+
0
===10/ / 好极了!
的规格详情+ []
:
这是一个迷宫,但要做 + []
,首先它被转换为字符串,因为这是 +
所说:
11.4.6一元+运算符
一元+运算符将其操作数转换为数字类型。
生产UnaryExpression :+ UnaryExpression评估如下:
设expr是评估UnaryExpression的结果。
返回ToNumber(GetValue(expr))。
ToNumber()
说:
对象
应用以下步骤:
让primValue为ToPrimitive(输入参数,提示字符串) )。
返回ToString(primValue)。
ToPrimitive()
说:
对象
返回Object的默认值。通过调用对象的[[DefaultValue]]内部方法,传递可选提示PreferredType来检索对象的默认值。 [[DefaultValue]]内部方法的行为由本规范为8.12.8中的所有本机ECMAScript对象定义。
[[DefaultValue]]
说:
8.12.8 [[DefaultValue]](提示)
当使用提示字符串调用O的[[DefaultValue]]内部方法时,将执行以下步骤:
设toString是使用参数toString调用对象O的[[Get]]内部方法的结果。
如果IsCallable(toString)为真,那么,
a。设str是调用toString的[[Call]]内部方法的结果,其中O为该值和空参数列表。
b。如果str是原始值,则返回str。
.toString
数组说:
15.4.4.2 Array.prototype.toString()
调用toString方法时,将执行以下步骤:
让数组成为调用ToObject的结果值。
让func成为使用参数join调用数组的[[Get]]内部方法的结果。
如果IsCallable(func)为false,则让func成为标准的内置方法Object.prototype.toString(15.2.4.2)。
返回调用func提供数组的[[Call]]内部方法的结果作为此值和空参数列表。
所以 + []
归结为 +
,因为 [] .join()===
。
再次, +
定义为:
11.4.6一元+运算符
一元+运算符将其操作数转换为数字类型。
生产的UnaryExpression:+ UnaryExpression评估如下:
让expr成为评估UnaryExpression的结果。
返回ToNumber(GetValue(expr))。
ToNumber
定义为 as:
StringNumericLiteral ::: [empty]的MV为0.
所以 +=== 0
,因此 + [] = == 0
。
This is valid and returns the string "10"
in JavaScript (more examples here):
console.log(++[[]][+[]]+[+[]])
Why? What is happening here?
If we split it up, the mess is equal to:
++[[]][+[]]
+
[+[]]
In JavaScript, it is true that +[] === 0
. +
converts something into a number, and in this case it will come down to +""
or 0
(see specification details below).
Therefore, we can simplify it (++
has precendence over +
):
++[[]][0]
+
[0]
Because [[]][0]
means: get the first element from [[]]
, it is true that:
[[]][0]
returns the inner array ([]
). Due to references it's wrong to say[[]][0] === []
, but let's call the inner arrayA
to avoid the wrong notation.++[[]][0] == A + 1
, since++
means 'increment by one'.++[[]][0] === +(A + 1)
; in other words, it will always be a number (+1
does not necessarily return a number, whereas++
always does - thanks to Tim Down for pointing this out).
Again, we can simplify the mess into something more legible. Let's substitute []
back for A
:
+([] + 1)
+
[0]
In JavaScript, this is true as well: [] + 1 === "1"
, because [] == ""
(joining an empty array), so:
+([] + 1) === +("" + 1)
, and+("" + 1) === +("1")
, and+("1") === 1
Let's simplify it even more:
1
+
[0]
Also, this is true in JavaScript: [0] == "0"
, because it's joining an array with one element. Joining will concatenate the elements separated by ,
. With one element, you can deduce that this logic will result in the first element itself.
So, in the end we obtain (number + string = string):
1
+
"0"
=== "10" // Yay!
Specification details for +[]
:
This is quite a maze, but to do +[]
, first it is being converted to a string because that's what +
says:
11.4.6 Unary + Operator
The unary + operator converts its operand to Number type.
The production UnaryExpression : + UnaryExpression is evaluated as follows:
Let expr be the result of evaluating UnaryExpression.
Return ToNumber(GetValue(expr)).
ToNumber()
says:
Object
Apply the following steps:
Let primValue be ToPrimitive(input argument, hint String).
Return ToString(primValue).
ToPrimitive()
says:
Object
Return a default value for the Object. The default value of an object is retrieved by calling the [[DefaultValue]] internal method of the object, passing the optional hint PreferredType. The behaviour of the [[DefaultValue]] internal method is defined by this specification for all native ECMAScript objects in 8.12.8.
[[DefaultValue]]
says:
8.12.8 [[DefaultValue]] (hint)
When the [[DefaultValue]] internal method of O is called with hint String, the following steps are taken:
Let toString be the result of calling the [[Get]] internal method of object O with argument "toString".
If IsCallable(toString) is true then,
a. Let str be the result of calling the [[Call]] internal method of toString, with O as the this value and an empty argument list.
b. If str is a primitive value, return str.
The .toString
of an array says:
15.4.4.2 Array.prototype.toString ( )
When the toString method is called, the following steps are taken:
Let array be the result of calling ToObject on the this value.
Let func be the result of calling the [[Get]] internal method of array with argument "join".
If IsCallable(func) is false, then let func be the standard built-in method Object.prototype.toString (15.2.4.2).
Return the result of calling the [[Call]] internal method of func providing array as the this value and an empty arguments list.
So +[]
comes down to +""
, because [].join() === ""
.
Again, the +
is defined as:
11.4.6 Unary + Operator
The unary + operator converts its operand to Number type.
The production UnaryExpression : + UnaryExpression is evaluated as follows:
Let expr be the result of evaluating UnaryExpression.
Return ToNumber(GetValue(expr)).
ToNumber
is defined for ""
as:
The MV of StringNumericLiteral ::: [empty] is 0.
So +"" === 0
, and thus +[] === 0
.
这篇关于为什么++ [[]] [+ []] + [+ []]返回字符串“10”?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!