为什么以及如何 ([![]]+[][[]])[+!+[]+[+[]]] 评估字母“i”? [重复]

问题描述 投票:0回答:2

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

下面的代码显然打印了字符串

"fail"

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

这涉及到隐式类型转换,我试图理解这行代码是如何被解释的。

我已经隔离了每个角色

  • (![]+[])[+[]]
    版画
    "f"
  • (![]+[])[+!+[]]
    版画
    "a"
  • ([![]]+[][[]])[+!+[]+[+[]]]
    版画
    "i"
  • (![]+[])[!+[]+!+[]]
    版画
    "l"

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

"i"

字母
"f"

![]
空数组是一个对象,根据 ECMAScript 文档,点 9.2 在转换为
true
时计算为
boolean
所以这是
false

false+[]
根据 Point 11.6.1 二元运算符
+
的两个参数都转换为字符串,因此我们得到
"false"+""
,它计算
"false"

+[]
如果参数是
ToNumber
,一元加运算符会导致
ToPrimitive
转换,然后是
Object
转换。这种转换的结果是通过调用对象的
[[DefaultValue]]
内部方法来确定的。如果是空数组,则默认为
0
。 (ECMAScript 文档,部分:11.4.69.39.1

"false"[0]
我们正在访问索引
0
处的字符,因此
"f"

字母
"a"

同一个故事,这里唯一的区别是方括号中的部分进行了额外的转换(计算为一个数字以指向字符串中的另一个字符

"false"
),由使用一元
+
!
运算符触发.

+[]
的计算结果为
0
,如上所述。

!0
的计算结果为
true
,如 Section 9.2Section 11.4.9 中所定义。首先,
0
被转换为布尔值
false
然后运算符反转值。

+true
再次,一元加号触发
ToNumber
转换,返回二进制
1
true
第 11.4.69.3

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

字母“l”

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

true+true
在基元上使用二进制
+
会触发
ToNumber
转换。如果为真,它的结果是
1
1+1
等于
2

"false"[2]
- 不言自明

字母
"i"

让我难过的是字母

"i"
。我可以看到第二部分(在方括号中)计算为字符串
"10"
并且第一部分(在括号中)返回
"falseundefined"
但是 我无法弄清楚这是如何发生的。有人可以一步一步解释吗? 尤其是方括号发生的魔法? (数组和数组访问)

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

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

[][[]]

javascript types obfuscation ecmascript-5
2个回答
40
投票

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

[]['']

[]
将被强制转换为字符串,因为它不是整数,因此您正在寻找
[]
的属性,其名称为
''
(空字符串)。你只会得到
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
部分的解释。


2
投票

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

([![]]+[][[]])
和你自己找到的另一个。

![]
返回
false
。然后我们使用
[...]
来获得
.toString()
+
行为。 (
[]+[]
[].toString()+[].toString()
相同)
[][[]]
未定义,因为我们试图访问未定义的
[]
的索引
[].toString()
(或
''
,即
[]
)。

© www.soinside.com 2019 - 2024. All rights reserved.