为什么以及(] + ]) + ]]的计算结果为字母“i”?
在阅读这篇贴在dzone上的文章时,我发现了由Marcus Lagergren最初在Twitter上发布的一段JavaScript代码。
下面的代码显然打印string"fail"
(![]+[])[+[]]+(![]+[])[+!+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]];
这涉及到隐式types转换,我试图理解这条线是如何解释的。
我已经隔离每个字符
-
(![]+[])[+[]]
打印"f"
-
(![]+[])[+!+[]]
打印"a"
-
([![]]+[][[]])[+!+[]+[+[]]]
打印"i"
-
(![]+[])[!+[]+!+[]]
打印"l"
我也设法分解expression式,从"i"
字母"f"
![]
一个空数组是一个对象,根据ECMAScript文档,点9.2在转换为boolean
时计算为true
,所以这是false
false+[]
按照第11.6.1节二进制+
运算符的两个参数都被转换为String,因此我们得到"false"+""
,其结果为"false"
+[]
一个加号运算符会导致一个ToNumber
转换,如果该参数是一个Object
则会进行ToPrimitive
转换。 这种转换的结果是通过调用对象的[[DefaultValue]]
内部方法来确定的。 如果数组为空,则默认为0
。 (ECMAScript文档,章节: 11.4.6,9.3,9.1 )
"false"[0]
我们访问索引为0
的字符,因此"f"
字母"a"
同样的故事,这里唯一的区别是方括号内的部分(通过使用一元+
和!
)触发的额外的转换(通过计算一个数字来指向string"false"
中的另一个字符) !
运营商。
如上所述, +[]
计算结果为0
。
如第9.2 节和第11.4.9 节中定义的那样, !0
评估为true
。 首先,将0
转换为布尔值false
,然后运算符将该值反转。
+true
再次为+true
,一元正则触发一个ToNumber
转换,它返回一个1
表示二进制true
( Section 11.4.6 and 9.3 )
"false"[1]
返回string中的第二个字符,即"a"
字母“l”
!+[]
计算结果如上所述
使用基元上的二进制+
true+true
触发ToNumber
转换。 如果是,则结果是1+1
等于2
"false"[2]
– 自我解释
字母"i"
让我难过的是字母"i"
。 我可以看到第二部分(在方括号内)的计算结果为string"10"
,第一部分(在括号内)返回"falseundefined"
但是我不能对这种情况做出 "falseundefined"
或 "falseundefined"
。 有人可以一步一步解释吗? 特别是用方括号发生的魔法? (数组和数组访问)
如果可能,我希望每一步都包含一个指向底层ECMAScript规则的链接。
我觉得最神秘的是这部分: [][[]]
如果你稍微改写一下,你的神秘部分并不是那么神秘:
[]['']
[]
将被强制为一个string,因为它不是一个整数,所以你正在寻找名称为''
(一个空string)的[]
属性。 你会得到undefined
,因为没有这个名字的财产。
至于实际的信件,把expression分成两个主要部分:
- string
([![]]+[][[]])
:-
[![]]
是[false]
。 -
[][[]]
undefined
。 - 将它们加在一起,就会得到
"falseundefined"
。
-
- 和索引:
[+!+[]+[+[]]]
。 一些空格和括号会使操作更清晰:[+(!(+[])) + [+[]]]
:-
[+[]]
是[0]
。 -
+[]
强制[]
为一个整数,所以你得到0
。 -
!+[]
0
强制为一个布尔值,否定它,这样你就可以了。 -
+!+[]
强制为一个整数,所以你得到1
。 - 把它们加在一起,就会得到
["10"]
。
-
使用string访问数组的属性时,string碰巧是数组的一个元素,string被强制为一个整数,并返回数组的实际元素:
> [1, 2, 3]["0"] 1 > [1, 2, 3]["1"] 2
所以你的最终结果是:
> "falseundefined"["10"] "i"
阅读这个答案 ,解释[false] + undefined
部分。
([![]]+[][[]])[+!+[]+[+[]]]
有两部分:
([![]]+[][[]])
和其他你发现自己。
![]
返回false
。 然后我们使用获取.toString()
行为。 ( []+[]
与[].toString()+[].toString()
相同[][[]]
是未定义的,因为我们试图访问index []
(或[].toString()
,这是未定义的[]
。
对不起以前的回答,我完全误解了你的评论。