为什么这个表达式在 JavaScript 中被计算为 "a"?

Why is this expression evaluated to "a" in JavaScript?

我得到了一些混淆的 JavaScript 代码。我试图理解它,然后在控制台中输入了一些片段。我不明白为什么

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

为什么((!!+[]+"")[+!![]])等于JavaScript中的"a"?是否有其他代码片段可以获取其他字母?

估计跟自动施法有关

( ( !!+[] + "" ) [ +!![] ] )
( (  !!0  + "" ) [ +true ] )
( ( false + "" ) [ +true ] )
( (   "false"  ) [   1   ] )
(         "false"[1]       )
(            "a"           ) 

Is there some other code snippets to get others letters ?

您可以使用相同的概念来获得来自 "true"、"false"、"undefined"、"NaN"...

的所有字母

您应该在 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"

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

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

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

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

继续前进,在 JavaScript 中,您可以将字符串想象成一个字符数组,您可以使用数组表示法访问它们的字符。

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

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

[] 是一个空数组,您可以将其视为 0,在 JavaScript 中是 true(因为 "in JavaScript anything 'real' is true"), 所以 ![] 是 false!![]true.

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

理解这一点的关键是要知道 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 conversions and operator precedence 的更多信息。

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

下面是详细的分步过程:

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

+[] 对数组字面量进行一元加法运算,等价于 Number([]) 结果为 0See this 为什么这个计算结果为 0

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

!!0 等同于 !!Boolean(0)) 的计算结果为 false 因为 0 是假值。

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

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

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

!![] 等同于 !!Boolean([]),因为对象的布尔转换 returns 始终为真。计算结果为 true

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

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

"false" [ 1 ]

最后是 a

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

Type Coercion