为什么这个表达式在 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([])
结果为 0
。
See 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 博士撰写的优秀资源
我得到了一些混淆的 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([])
结果为 0
。
See 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 博士撰写的优秀资源