Why does ++[[]][+[]]+[+[]] return the string “10”?
这是有效的,并返回javascript中的字符串
1 | console.log(++[[]][+[]]+[+[]]) |
为什么?这里发生了什么?
如果我们把它分开,混乱就等于:
1 2 3 | ++[[]][+[]] + [+[]] |
在javascript中,
因此,我们可以简化它(
1 2 3 | ++[[]][0] + [0] |
因为
[[]][0] 返回内部数组([] )。由于引用的原因,说[[]][0] === [] 是错误的,但是让我们调用内部数组A 以避免错误的符号。++[[]][0] == A + 1 ,因为++ 表示"增量1"。++[[]][0] === +(A + 1) ;换句话说,它总是一个数字(+1 不一定返回一个数字,而++ 总是返回一个数字,这要归功于蒂姆指出了这一点)。
同样,我们可以将混乱简化为更清晰的内容。让我们用
1 2 3 | +([] + 1) + [0] |
在javascript中,这也是正确的:
+([] + 1) === +("" + 1) 和+("" + 1) === +("1") 和+("1") === 1
让我们进一步简化它:
1 2 3 | 1 + [0] |
另外,在javascript:
因此,最后我们得到(数字+字符串=字符串):
1 2 3 4 5 | 1 + "0" ==="10" // Yay! |
这是一个相当复杂的迷宫,但对于
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)).
Object
Apply the following steps:
Let primValue be ToPrimitive(input argument, hint String).
Return ToString(primValue).
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.
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.
数组的
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.
因此,
同样,
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)).
The MV of StringNumericLiteral ::: [empty] is 0.
因此,
1 2 | ++[[]][+[]] => 1 // [+[]] = [0], ++0 = 1 [+[]] => [0] |
然后我们有一个字符串连接
1 | 1+[0].toString() = 10 |
以下内容改编自一篇博客文章,回答了我在这个问题还未解决时发表的这个问题。链接是到ecmascript 3规范的(HTML副本),这仍然是当前常用Web浏览器中javascript的基线。
首先,一个注释:这种表达式永远不会出现在任何(健全的)生产环境中,它只是作为一个练习,在读者了解javascript的脏边方面有多好。JavaScript运算符在类型之间隐式转换的一般原则是有用的,与一些常见的转换一样,但在本例中,大部分细节不是这样的。
表达式
1 | ( ++[[]][+[]] ) + ( [+[]] ) |
把这个分解,我们可以通过观察
1 | ( ++[[]][0] ) + [0] |
已经简单了。对于
所以,我们可以把
那么,
这让我们
1 | 1 + [0] |
…这是加法运算符的简单用法。两个操作数都首先转换为基元,如果其中一个基元值是字符串,则执行字符串串联,否则执行数字加法。
最后一点,可能不立即明显的是,重写
1 2 3 4 | Array.prototype.toString = function() { return"foo"; }; ++[[]][+[]]+[+[]] |
…生产
让我们简单点:
1 2 3 4 5 6 7 8 9 10 11 12 13 | ++[[]][+[]]+[+[]] ="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" |
这一个的计算结果相同,但有点小
1 | +!![]+''+(+[]) |
- []-是一个数组被转换,当您对其进行加或减操作时,该数组被转换为0,因此+[]=0
- ![]-计算结果为假,因此!![]计算为真
- +!![]-将true转换为计算结果为true的数值,因此在本例中为1
- +""-向表达式追加空字符串,导致数字转换为字符串
- +[]-计算结果为0
评估结果也是如此
1 2 3 | +(true) + '' + (0) 1 + '' + 0 "10" |
现在你明白了,试试这个:
1 | _=$=+[],++_+''+$ |
+[]的计算结果为0[…]然后用任何东西对它求和(+operation),将数组内容转换为由逗号连接的元素组成的字符串表示形式。
任何其他像获取数组索引(比+操作优先级高)的操作都是有序的,没有什么有趣的。
可能将表达式计算为"10"而不带数字的最短方法是:
//说明==\
然后JS对
一些例子:
1 2 3 | 1 + {} // "1[object Object]" 1 + [] // "1" 1 + new Date() // "1Wed Jun 19 2013 12:13:25 GMT+0400 (Caucasus Standard Time)" |
有一个很好的例外,两个
1 2 3 4 5 | [] + [] // "" [1] + [2] // "12" {} + {} // NaN {a:1} + {b:2} // NaN [1, {}] + [2, {}] // "1,[object Object]2,[object Object]" |
+""或+[]的计算结果为0。
1 2 3 4 | ++[[]][+[]]+[+[]] = 10 ++[''][0] + [0] : First part is gives zeroth element of the array which is empty string 1+0 10 |
一步一步地,
从那里开始,现在看看你的代码,它是
它们之间还有一个加号:
所以这些
想象一下,第一个值是一个二维数组,里面有一个数组…所以
最后,将其转换为
所以你可以想象,