【问题标题】:Why is this expression evaluated to "a" in JavaScript? [duplicate]为什么这个表达式在 JavaScript 中被评估为“a”? [复制]
【发布时间】:2017-10-28 23:13:45
【问题描述】:

我得到了一些混淆的 JavaScript 代码。我试图理解它,并且这样做,我在控制台中输入了它的一部分。我不明白为什么

> ((!!+[]+"")[+!![]])
< "a"

为什么 ((!!+[]+"")[+!![]]) 在 JavaScript 中等于 "a"?有没有其他的代码sn-ps来获取别人的字母?

我猜这与自动投射有关。

【问题讨论】:

  • 这整件事可以简化为("false"[1])。现在你知道为什么结果是a了。
  • a 是 false 的第二个字母。聪明的^^
  • @abhishekkannojia 为什么(!!+[]+"") 等于"false" 以及为什么+!![] 等于1

标签: javascript types obfuscation deobfuscation


【解决方案1】:
( ( !!+[] + "" ) [ +!![] ] )
( (  !!0  + "" ) [ +true ] )
( ( false + "" ) [ +true ] )
( (   "false"  ) [   1   ] )
(         "false"[1]       )
(            "a"           ) 

还有其他代码 sn-ps 来获取其他字母吗?

您可以使用相同的概念来获取“true”、“false”、“undefined”、“NaN”...中的所有字母......

【讨论】:

  • 这是正确的答案。
  • 为什么+[] 等于0?猜猜它会将空数组转换为数字,所以,为什么不 0... 但我认为这值得一小行...如果可能的话,比我的猜测要好:)
  • @HuguesMoreau 一元加运算+[] 解析为数字类型
【解决方案2】:

您应该在 JavaScript 中处理运算符优先级和类型转换:

!!+[] // Is falsey. this is same for !!+0 or !!+""
false + "" // Is "false". as 5+"" is "5".

![] // Is falsey.
!false // Is true
+true //  Is equal to 1. +[] = 0, +false = 0

至少,

"false"[1] // Is "a"

【讨论】:

【解决方案3】:

假设我们不知道这意味着什么,让我们使用控制台来获取答案,输入

[] + "" 在控制台输出""

只需输入(!!+[]) 即可返回布尔值false。如果将布尔值 false 附加到 "",由于类型强制,您会得到字符串 false

正如预期的那样,输入(!!+[]+"") 会将"false" 输出到控制台。

接下来,在 JavaScript 中,您可以将字符串视为字符数组,您可以使用数组表示法访问它们的字符。

因此,在((!!+[]+"")[+!![]]) 中,您可以删除最外面的括号以使其看起来更简单。现在我们有了(!!+[]+"")[+!![]],其中() 的第一部分返回字符串"false"[] 的下一部分访问字符串"false" 的一个字符。您现在可以打赌 +!![] 以某种方式返回 1,因为 "false"[1] 等于 "a"

现在让我们看看+!![] 等于1

[] 是一个空数组,您可以将其视为0,在 JavaScript 中将是 true(因为 “在 JavaScript 中任何“真实”都是 true),所以 ![] 是 false!![]true

现在我们剩下+true,它只是将true 转换为1 的数字的简写。现在您可以看到 +!![] 如何计算为 1 并且您(希望)理解了那段混淆代码的工作原理!

【讨论】:

    【解决方案4】:

    理解这一点的关键是要知道 JavaScript 会进行隐式类型转换来评估它看到的表达式。换句话说,虽然您可能不知道将数字添加到字符串中意味着什么,但 JavaScript 会进行猜测而不是发出错误。这与您在 C++ 中得到的相反,在这种情况下会给出明确的错误。

    例如,+x 总是计算为一个数字,不管 x 实际上是什么类型。 !x 也一样。因此,对于你的表达:

    // A: !!+[]+"" which is evaluated like !(!(+[]))+""
    +[]       === 0
    !0        === true
    !true     === false
    false+''  === 'false'
    
    // B: +!![] which is evaluated like +(!(![]))
    ![]       === false
    !false    === true
    +true     === 1
    

    我们得到A[B],它就是'false'[1] === 'a'

    您可以在 MDN 上了解有关 implicit type conversionsoperator precedence 的更多信息。

    隐式类型转换是经验丰富的 JavaScript 程序员在比较值时更喜欢使用 === 而不是 == 的原因。

    【讨论】:

      【解决方案5】:

      这里是正在发生的事情的详细分步过程:

      ( !! +[] + "" ) [ +!![] ]
      //   ^^^ 
      

      +[] 一元加数组字面量运算,相当于Number([]) 导致0See this 为什么这会评估为 0

      ( !! 0 + "" ) [ +!![] ]
      //^^^^
      

      !!0 等价于!!Boolean(0)),其计算结果为false,因为0 是假值。

      ( false + "" ) [ +!![] ]
      //^^^^^^^^^^^
      

      false+"" 是简单的字符串连接,因此计算结果为 "false"

      "false" [ +!![] ]
      //         ^^^^ 
      

      !![] 等价于!!Boolean([]) 并且因为对象的布尔转换总是返回真。这评估为true

      "false" [ +true ]
      //        ^^^^^
      

      +true 等价于 Number(true),其计算结果为 1

      "false" [ 1 ]
      

      最后是a

      这里的关键是 Javascript 在计算表达式时会进行隐式类型转换或类型强制。要了解有关类型强制的更多信息,我建议使用 Axel Rauschmayer 博士编写的优秀资源

      Type Coercion

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-02-20
        • 1970-01-01
        • 2013-10-20
        • 2020-04-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-05-06
        相关资源
        最近更新 更多