为什么以及(] + ]) + ]]的计算结果为字母“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() ,这是未定义的[]

对不起以前的回答,我完全误解了你的评论。