在阅读dzone 上发布的这篇文章时,我发现了一段 JavaScript 片段,最初由 Marcus Lagergren 发布在 Twitter 上。
以下代码显然打印了字符串 "fail"
(![]+[])[+[]]+(![]+[])[+!+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]];
这涉及隐式类型转换,我试图了解如何准确解释这一行。
我已经隔离了每个角色
(![]+[])[+[]]
印刷"f"
(![]+[])[+!+[]]
印刷"a"
([![]]+[][[]])[+!+[]+[+[]]]
印刷"i"
(![]+[])[!+[]+!+[]]
印刷"l"
我还设法分解了返回每个字母的表达式 "i"
信 "f"
![]
空数组是一个对象,根据ECMAScript 文档,true
当转换为 a 时,点 9.2 的计算结果boolean
为false
false+[]
根据第 11.6.1 点,二元+
运算符的两个参数都被转换为字符串,因此我们得到"false"+""
,它计算"false"
+[]
如果参数是一个,一元加运算符会导致一个ToNumber
转换,然后是一个ToPrimitive
转换Object
。这种转换的结果是通过调用[[DefaultValue]]
对象的内部方法来确定的。如果是空数组,则默认为0
。(ECMAScript 文档,章节:11.4.6 , 9.3 , 9.1)
"false"[0]
我们正在访问 index 处的字符0
,因此"f"
信 "a"
同样的故事,这里唯一的区别是方括号中部分的额外转换(计算结果为一个数字以指向字符串中的另一个字符"false"
),由使用一元+
和!
运算符触发。
+[]
评估为0
,如上所述。
!0
计算true
为第 9.2节和第 11.4.9 节中的定义。首先,0
转换为布尔值false
,然后运算符反转该值。
+true
再次,一元加号触发ToNumber
转换,返回一个1
for binary true
(第 11.4.6和9.3节)
"false"[1]
返回字符串中的第二个字符,即 "a"
字母“l”
!+[]
评估true
为如上所述
true+true
+
在原语上使用二进制会触发ToNumber
转换。在为真的情况下,它的结果是1
并且1+1
等于2
"false"[2]
- 不言自明
信 "i"
让我难住的是那封信"i"
。我可以看到第二部分(在方括号中)计算结果为字符串"10"
,第一部分(在括号中)返回,"falseundefined"
但我无法弄清楚这是如何发生的。有人能一步一步解释吗?特别是方括号发生的魔法?(数组和数组访问)
如果可能,我希望每个步骤都包含一个指向底层 ECMAScript 规则的链接。
我觉得最神秘的是这部分: [][[]]