这是有效的,并返回"10"
JavaScript中的字符串(此处有更多示例):
console.log(++[[]][+[]]+[+[]])
为什么?这是怎么回事
可能的最短方法是将表达式评估为没有数字的“ 10”:
+!+[] + [+[]]
//“ 10”
-~[] + [+[]]
//“ 10”
// ==========说明========= \\
+!+[]
:+[]
转换为0。!0
转换为true
。+true
转换为1
-~[]
= = -(-1)
1
[+[]]
:+[]
转换为0。[0]
是具有单个元素0的数组。
然后JS计算1 + [0]
,即Number + Array
表达式。然后ECMA规范起作用:+
运算符通过toString()/valueOf()
从基本Object
原型中调用函数将两个操作数转换为字符串。如果一个表达式的两个操作数都只有数字,则它可以作为加法函数。诀窍在于,数组可以轻松地将其元素转换为连接的字符串表示形式。
一些例子:
1 + {} // "1[object Object]"
1 + [] // "1"
1 + new Date() // "1Wed Jun 19 2013 12:13:25 GMT+0400 (Caucasus Standard Time)"
有一个很好的例外,有两个Objects
加法导致NaN
:
[] + [] // ""
[1] + [2] // "12"
{} + {} // NaN
{a:1} + {b:2} // NaN
[1, {}] + [2, {}] // "1,[object Object]2,[object Object]"
+''或+ []的值为0。
++[[]][+[]]+[+[]] = 10
++[''][0] + [0] : First part is gives zeroth element of the array which is empty string
1+0
10
+ []的计算结果为0 [...],然后将其与任何内容求和(+操作),将数组内容转换为其字符串表示形式,该字符串表示形式包含用逗号连接的元素。
像获取数组索引(具有比+操作更高的优先级)之类的其他东西都是有序的,没什么有趣的。
++[[]][+[]] => 1 // [+[]] = [0], ++0 = 1
[+[]] => [0]
然后我们有一个字符串连接
1+[0].toString() = 10
该评估结果相同但略小
+!![]+''+(+[])
所以估计
+(true) + '' + (0)
1 + '' + 0
"10"
所以现在您明白了,尝试以下方法:
_=$=+[],++_+''+$
以下内容是根据一个博客帖子改编的,该博客帖子回答了我在此问题仍处于关闭状态时发布的该问题。链接指向ECMAScript 3规范(的HTML副本),仍然是当今常用的Web浏览器中JavaScript的基线。
首先,发表评论:这种表达永远不会出现在任何(理智的)生产环境中,并且只能用作练习,以了解读者如何了解JavaScript的肮脏边缘。JavaScript运算符在类型之间进行隐式转换的一般原理以及一些常见的转换都是有用的,但本例中的许多细节都没有。
该表达式++[[]][+[]]+[+[]]
最初看起来可能比较强悍和晦涩,但实际上相对容易分解为单独的表达式。为了清楚起见,我在下面仅添加了括号。我可以向您保证,他们什么都不会改变,但是如果您想验证这一点,请随时阅读有关分组运算符的信息。因此,该表达式可以更清楚地写为
( ++[[]][+[]] ) + ( [+[]] )
打破这一下来,我们可以通过观察来简化+[]
计算结果为0
。为了使自己满意,请检查一元+运算符,并遵循略带曲折的轨迹,该轨迹最终以ToPrimitive将空数组转换为空字符串,然后最终0
由ToNumber转换为空字符串。现在0
,我们可以代替的每个实例+[]
:
( ++[[]][0] ) + [0]
已经更简单了。至于++[[]][0]
,这是前缀增量运算符(++
),定义单个元素的数组的数组文字的组合,该元素本身就是一个空数组([[]]
)和在该数组文字所定义的数组上调用的属性访问器([0]
)。
So, we can simplify [[]][0]
to just []
and we have ++[]
, right? In fact, this is not the case because evaluating ++[]
throws an error, which may initially seem confusing. However, a little thought about the nature of ++
makes this clear: it’s used to increment a variable (e.g. ++i
) or an object property (e.g. ++obj.count
). Not only does it evaluate to a value, it also stores that value somewhere. In the case of ++[]
, it has nowhere to put the new value (whatever it may be) because there is no reference to an object property or variable to update. In spec terms, this is covered by the internal PutValue operation, which is called by the prefix increment operator.
So then, what does ++[[]][0]
do? Well, by similar logic as +[]
, the inner array is converted to 0
and this value is incremented by 1
to give us a final value of 1
. The value of property 0
in the outer array is updated to 1
and the whole expression evaluates to 1
.
This leaves us with
1 + [0]
... which is a simple use of the addition operator. Both operands are first converted to primitives and if either primitive value is a string, string concatenation is performed, otherwise numeric addition is performed. [0]
converts to "0"
, so string concatenation is used, producing "10"
.
最后,可能不会立即显而易见的是,覆盖的toString()
或valueOf()
方法之一Array.prototype
将更改表达式的结果,因为在将对象转换为原始值时会同时检查和使用两者(如果存在)。例如,以下
Array.prototype.toString = function() {
return "foo";
};
++[[]][+[]]+[+[]]
...产生"NaNfoo"
。为什么发生这种情况留给读者作为练习...
让我们简单点:
++[[]][+[]]+[+[]] = "10"
var a = [[]][+[]];
var b = [+[]];
// so a == [] and b == [0]
++a;
// then a == 1 and b is still that array [0]
// when you sum the var a and an array, it will sum b as a string just like that:
1 + "0" = "10"
逐步操作,
+
将value转换为数字,如果您将其添加到一个空数组中+[]
,因为它为空且等于0
,它将所以从那里开始,现在查看您的代码,它是
++[[]][+[]]+[+[]]
...他们之间有加号
++[[]][+[]]
+[+[]]
所以这些
[+[]]
将返回,[0]
因为它们有一个空数组,该数组将被转换为0
另一个数组内部...就像想象的那样,第一个值是一个二维数组,其中包含一个数组...因此
[[]][+[]]
等于[[]][0]
返回的值[]
...最后
++
将其转换并增加到1
...因此,您可以想象,
1
+"0"
将"10"
...