([![]]+[][[]])[+!+[]+[+[]]] 为什么以及如何计算为字母“i”?

IT技术 javascript 类型 混淆 ecmascript-5
2021-02-22 14:46:49

在阅读dzone 上发布的这篇文章时,我发现了一段 JavaScript 片段,最初由 Marcus Lagergren 发布在 Twitter 上

以下代码显然打印了字符串 "fail"

(![]+[])[+[]]+(![]+[])[+!+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]];

这涉及隐式类型转换,我试图了解如何准确解释这一行。

我已经隔离了每个角色

  • (![]+[])[+[]] 印刷 "f"
  • (![]+[])[+!+[]] 印刷 "a"
  • ([![]]+[][[]])[+!+[]+[+[]]] 印刷 "i"
  • (![]+[])[!+[]+!+[]] 印刷 "l"

我还设法分解了返回每个字母的表达式 "i"

"f"

![]空数组是一个对象,根据ECMAScript 文档,true当转换为 a 时,点 9.2 的计算结果booleanfalse

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转换,返回一个1for binary true第 11.4.69.3

"false"[1] 返回字符串中的第二个字符,即 "a"

字母“l”

!+[]评估true为如上所述

true+true+在原语上使用二进制会触发ToNumber转换。在为真的情况下,它的结果是1并且1+1等于2

"false"[2] - 不言自明

"i"

让我难住的是那封信"i"我可以看到第二部分(在方括号中)计算结果为字符串"10",第一部分(在括号中)返回,"falseundefined"我无法弄清楚这是如何发生的。有人能一步一步解释吗?特别是方括号发生的魔法?(数组和数组访问)

如果可能,我希望每个步骤都包含一个指向底层 ECMAScript 规则的链接。

我觉得最神秘的是这部分: [][[]]

2个回答

如果你稍微重写一下,你的神秘部分就不是那么神秘了:

[]['']

[]将被强制转换为字符串,因为它不是整数,因此您正在寻找[]具有名称的属性''(空字符串)。您只会得到undefined,因为没有具有该名称的属性。

至于实际的字母,将表达式分解为两个主要部分:

  • 字符串([![]]+[][[]])
    • [![]][false]
    • [][[]]undefined
    • 把它们加在一起,你就得到了"falseundefined"
  • 和索引:[+!+[]+[+[]]]一些空格和括号将使操作更加清晰[+(!(+[])) + [+[]]]::
    • [+[]][0]
    • +[]强制[]为整数,所以你得到0.
    • !+[]强制0为布尔值并否定它,所以你得到true.
    • +!+[]强制true为整数,所以你得到1.
    • 把它们加在一起,你就得到了["10"]

当使用字符串访问数组的属性并且该字符串恰好是该数组的一个元素时,该字符串被强制转换为一个整数,您将返回该数组的实际元素:

> [1, 2, 3]["0"]
1
> [1, 2, 3]["1"]
2

所以你的最终结果是:

> "falseundefined"["10"]
"i"

阅读此答案了解[false] + undefined部分的说明

([![]]+[][[]])[+!+[]+[+[]]] 有两部分:

([![]]+[][[]]) 另一个是你自己发现的。

![]返回false然后我们使用[...]来获取 的.toString()行为+([]+[][].toString()+[].toString()) the [][[]]is undefined 因为我们试图访问其未定义的索引[](或[].toString(), which is '') []

抱歉之前的回答,我完全误读了您的评论。