这个问题在这里已有答案:
在阅读this article posted on dzone时,我发现了一段JavaScript,最初是posted on Twitter by Marcus Lagergren .
以下代码显然打印字符串 "fail"
(![]+[])[+[]]+(![]+[])[+!+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]];
这涉及隐式类型转换,我试图理解这条线的解释方式 .
我已经隔离了每个角色
-
(![]+[])[+[]]
打印"f"
-
(![]+[])[+!+[]]
打印"a"
-
([![]]+[][[]])[+!+[]+[+[]]]
打印"i"
-
(![]+[])[!+[]+!+[]]
打印"l"
我还成功地将每个字母的表达式分解为 "i"
字母“f”
![]
一个空数组是一个Object,根据ECMAScript documentation, point 9.2在转换为 boolean
时求值为 true
所以这是 false
false+[]
根据Point 11.6.1二进制 +
运算符的两个参数都转换为String,因此我们得到 "false"+""
,它评估 "false"
+[]
如果参数为 Object
,则一元加号运算符会导致 ToNumber
转换,然后进行 ToPrimitive
转换 . 通过调用对象的 [[DefaultValue]]
internal方法来确定此类转换的结果 . 如果是空数组,则默认为 0
. (ECMAScript文档,部分:11.4.6,9.3,9.1)
"false"[0]
我们正在访问索引 0
处的字符,因此 "f"
字母“a”
同样的故事,这里唯一的区别是方括号中的部分中的额外转换(其评估为指向字符串 "false"
中的另一个字符的数字),由使用一元 +
和 !
运算符触发 .
+[]
评估为 0
,如上所述 .
!0
根据Section 9.2和Section 11.4.9中的定义求值为 true
. 首先,将 0
转换为布尔值 false
,然后运算符将该值反转 .
+true
再次,一元加号触发 ToNumber
转换,返回 1
为二进制 true
(Section 11.4.6和9.3)
"false"[1]
返回字符串中的第二个字符,即 "a"
字母“l”
如上所述, !+[]
评估为 true
true+true
在原语上使用二进制 +
触发 ToNumber
转换 . 如果为true,则其结果为 1
且 1+1
等于 2
"false"[2]
- 自我解释
字母“我”
令我难过的是字母 "i"
. 我可以看到第二部分(在方括号中)计算字符串 "10"
并且第一部分(在括号中)返回 "falseundefined"
但是 I can't make heads or tails of how this is happening. Could someone explain it step by step? 特别是方括号中出现的魔法? (数组和数组访问)
If possible, I'd like each step to contain a link to the underlying ECMAScript rules.
我发现最神秘的是这部分: [][[]]
2 回答
如果你重写一下,你的神秘部分并不是那么神秘:
[]
将被强制转换为字符串,因为它没有't an integer, so you'正在查找名称为''
(空字符串)的[]
属性 . 您将获得undefined
,因为没有具有该名称的属性 .至于实际的字母,将表达式分解为两个主要组成部分:
字符串
([![]]+[][[]])
:[![]]
是[false]
.[][[]]
是undefined
.将它们加在一起就可以得到 "falseundefined".
和索引:
[+!+[]+[+[]]]
. 一些空格和括号将使操作更清晰:[+(!(+[])) + [+[]]]
:[+[]]
是 [0] .+[]
将[]
强制为整数,因此您获得0
.!+[]
强制0
到布尔值并否定它,所以你得到true
.+!+[]
将true
强制为整数,因此您获得 1 .将它们组合在一起,就得到
["10"]
.当使用字符串访问数组的属性并且字符串恰好是数组的元素时,字符串被强制转换为整数并返回数组的实际元素:
所以你的最终结果是:
阅读this answer以获取
[false] + undefined
部分的说明 .([![]]+[][[]])[+!+[]+[+[]]]
有两部分:([![]]+[][[]])
和你发现的另一个 .![]
返回false
. 然后我们使用[...]
来获取+
的.toString()
行为 . ([]+[]
与[].toString()+[].toString()
相同)[][[]]
未定义,因为我们正在尝试访问未定义的[]
索引[]
(或[].toString()
,即''
) .对不起以前的回答,我完全误读了你的评论 .